diff --git a/modules/build/build.py b/modules/build/build.py new file mode 100644 index 000000000..4bcfd582b --- /dev/null +++ b/modules/build/build.py @@ -0,0 +1,1661 @@ +import sys, os, types, re, fnmatch, subprocess, shutil, platform, inspect +from os.path import split, isdir, isfile, exists, splitext, abspath, join, \ + basename, dirname + +from waflib import Options, Utils, Logs, TaskGen +from waflib.Configure import conf, ConfigurationContext +from waflib.Build import BuildContext, ListContext, CleanContext, InstallContext +from waflib.TaskGen import task_gen, feature, after, before +from waflib.Utils import to_list as listify +from waflib.Tools import waf_unit_test +from waflib import Context, Errors +from msvs import msvs_generator +from dumpenv import dumpenv + +COMMON_EXCLUDES = '.bzr .bzrignore .git .gitignore .svn CVS .cvsignore .arch-ids {arch} SCCS BitKeeper .hg _MTN _darcs Makefile Makefile.in config.log'.split() +COMMON_EXCLUDES_EXT ='~ .rej .orig .pyc .pyo .bak .tar.bz2 tar.gz .zip .swp'.split() + +if sys.version_info < (2,6,0): + raise Errors.WafError('Build system requires at least Python 2.6') + +# provide a partial function if we don't have one +try: + from functools import partial +except: + def partial(fn, *cargs, **ckwargs): + def call_fn(*fargs, **fkwargs): + d = ckwargs.copy() + d.update(fkwargs) + return fn(*(cargs + fargs), **d) + return call_fn + +class CPPContext(Context.Context): + """ + Create a custom context for building C/C++ modules/plugins + """ + cmd='evil' + module_hooks = [] + + def safeVersion(self, version): + return re.sub(r'[^\w]', '.', version) + + def __getDefines(self, env): + defines = [] + for line in env.DEFINES: + split = line.split('=') + k = split[0] + v = len(split) == 2 and split[1] or '1' + if v is not None and v != (): + if k.startswith('HAVE_') or k.startswith('USE_'): + defines.append(k) + else: + defines.append('%s=%s' % (k, v)) + return defines + + def pprint(self, *strs, **kw): + colors = listify(kw.get('colors', 'blue')) + colors = map(str.upper, colors) + for i, s in enumerate(strs): + sys.stderr.write("%s%s " % (Logs.colors(colors[i % len(colors)]), s)) + sys.stderr.write("%s%s" % (Logs.colors.NORMAL, os.linesep)) + + # because we can't assume python 2.6 + def __computeRelPath(self, rel, frm) : + + rel = abspath(rel) + frm = abspath(frm) + + relList = rel.split(os.sep) + fromList = frm.split(os.sep) + + for folder in fromList : + if len(relList) > 0 and relList[0] == folder : + relList.remove(folder) + return join(*relList) + + # find what should be excluded + def __dontDist (self, name, src, pkgExcludes, build_dir): + + # if initialized to the list, it was residually appending + # multiple version, so we start with an empty list + excludes = [] + dist_exts = [] + excludes.extend(COMMON_EXCLUDES) + dist_exts.extend(COMMON_EXCLUDES_EXT) + + for ex in pkgExcludes : + excludes.append(join(str(self.path), ex)) + dist_exts.extend(pkgExcludes) + + if (name.startswith(',,') or name.startswith('++') or name.startswith('.waf-1.') or \ + (src=='.' and name == Options.lockfile) or name in excludes or name == build_dir or \ + join(src, name) in excludes or name == "" and src in excludes): + return True + for ext in dist_exts : + if name.endswith(ext) : + return True + + return False + + # copy the entire directory minus certain things excluded -- + # this takes walking over individual elements + def copyTree(self, src, dst, pkgExcludes, build_dir): + + if self.__dontDist("", src, pkgExcludes, build_dir): + return + + names = os.listdir(src) + if not exists(dst) : + os.makedirs(dst) + + for name in names: + srcname = join(src, name) + dstname = join(dst, name) + + # build_dir is just to safeguard the dest being in the checkout area + if self.__dontDist(name, src, pkgExcludes, build_dir): + continue + if isdir(srcname): + self.copyTree(srcname, dstname, pkgExcludes, build_dir) + else: + shutil.copy2(srcname, dstname) + + def removeDuplicates(self, lst) : + # remove duplicates + if lst : + lst.sort() + last = lst[-1] + for i in range(len(lst)-2, -1, -1): + if lst[i] == '' or last == lst[i] : + del lst[i] + else: + last = lst[i] + return lst + + # copies source to the output location + def __makeSourceDelivery(self, dirs) : + + variant = self.env['VARIANT'] or 'default' + env = self.all_envs[variant] + + wafDir = abspath('./') + if isinstance(dirs, str): + dirs = dirs.split() + for dir in dirs : + if dir is None : + continue + + dir = join(self.path.abspath(), dir) + relPath = self.__computeRelPath(dir, wafDir) + + # find things in env + deliverSource = env['DELIVER_SOURCE'] + prefix = env['PREFIX'] + + # parse package excludes + pkgs = [] + if Options.options.packages : + pkgs = Options.options.packages.split(',') + pkgsExcludes = [] + for pkg in pkgs : + pkg = pkg.upper() + pkg = pkg.strip() + if pkg in env['BUILD_PACKAGES'] : + pkgsExcludes.extend(env['BUILD_PACKAGES'][pkg]['SOURCE_EXCLUDES']) + + pkgsExcludes = self.removeDuplicates(pkgsExcludes) + + if self.is_install and exists(dir) and deliverSource is True : + relPath = self.__computeRelPath(dir, wafDir) + + # convert relative excluded paths to full paths + parsedExcludes = [] + for pkgEx in pkgsExcludes: + dir = abspath(join(wafDir, pkgEx)) + if exists(dir) : + parsedExcludes.append(dir) + else : + parsedExcludes.append(pkgEx) + + # deliver all source from relPath recursively + self.copyTree(join(wafDir, relPath), + join (prefix, 'source', relPath), + parsedExcludes, prefix) + + + # wrapper function for delivering everything below a wscript pickup + def __add_subdirs_withSource(self, dirs) : + + if dirs is None : + return + if isinstance(dirs, str): + dirs = dirs.split() + for dir in dirs : + if dir is None : + continue + + self.__makeSourceDelivery(dir) + if not exists(join(self.path.abspath(), dir, 'wscript')) : + self.fromConfig(dir) + else : + self.recurse(dir) + + # wrapper function for delivering everything below a project.cfg pickup + def __fromConfig_withSource(self, dirs, **overrides) : + + if dirs is None : + return + self.__makeSourceDelivery(dirs) + self.fromConfig(dirs, **overrides) + + + + + def fromConfig(self, path, **overrides): + bld = self + from ConfigParser import SafeConfigParser as Parser + cp = Parser() + + if (type(path) != str): + path = path.abspath() + + if isdir(path): + for f in 'project.cfg module.cfg project.ini module.ini'.split(): + configFile = join(path, f) + if isfile(configFile): + cp.read(configFile) + path = configFile + break + elif isfile(path): + cp.read(path) + + sectionDict = lambda x: dict(cp.items(filter(lambda x: cp.has_section(x), [x, x.lower(), x.upper()])[0])) + + args = sectionDict('module') + args.update(overrides) + + if 'path' not in args: + if 'dir' in args: + args['path'] = bld.path.find_dir(args.pop('dir')) + else: + pardir = abspath(dirname(path)) + curdir = bld.path.abspath() + if pardir.startswith(curdir): + relDir = './%s' % pardir[len(curdir):].lstrip(os.sep) + args['path'] = bld.path.find_dir(relDir) + else: + args['path'] = bld.path + + #get the env + if 'env' in args: + env = args['env'] + else: + variant = args.get('variant', bld.env['VARIANT'] or 'default') + env = bld.all_envs[variant] + + # do some special processing for the module + excludes = args.pop('exclude', None) + if excludes is not None: + if type(excludes) == str: + args['source_filter'] = partial(lambda x, t: basename(str(t)) not in x, + excludes.split()) + elif 'source' in args: + source = args.pop('source', None) + if type(source) == str: + args['source_filter'] = partial(lambda x, t: basename(t) in x, + source.split()) + + try: + testArgs = sectionDict('tests') + excludes = testArgs.pop('exclude', None) + if excludes is not None: + if type(excludes) == str: + args['test_filter'] = partial(lambda x, t: basename(t) not in x, + excludes.split()) + elif 'source' in testArgs: + source = testArgs.pop('source', None) + if type(source) == str: + args['test_filter'] = partial(lambda x, t: basename(t) in x, + source.split()) + except Exception:{} + + try: + testArgs = sectionDict('unittests') + excludes = testArgs.pop('exclude', None) + if excludes is not None: + if type(excludes) == str: + args['unittest_filter'] = partial(lambda x, t: basename(t) not in x, + excludes.split()) + elif 'source' in testArgs: + source = testArgs.pop('source', None) + if type(source) == str: + args['unittest_filter'] = partial(lambda x, t: basename(t) in x, + source.split()) + except Exception:{} + + self.module(**args) + + try: + progArgs = sectionDict('programs') + files = progArgs.pop('files', '') + for f in files.split(): + parts = f.split('|', 2) + self.program_helper(module_deps=args['name'], source=parts[0], + path=args['path'], + name=basename(splitext(len(parts) == 2 and parts[1] or parts[0])[0])) + + except Exception:{} + + def build_packages(self, packages) : + + variant = self.env['VARIANT'] or 'default' + env = self.all_envs[variant] + + if isinstance(packages, str): + packages = packages.split(',') + + # parse packages + pkgsDirs = [] + pkgsTargets = [] + pkgsIncludes = [] + pkgsExcludes = [] + for package in packages : + if package is None : + continue + package = package.upper() + package = package.strip() + + pkgsDirs.extend(env['BUILD_PACKAGES'][package]['SUB_DIRS']) + pkgsTargets.extend(env['BUILD_PACKAGES'][package]['TARGETS']) + pkgsIncludes.extend(env['BUILD_PACKAGES'][package]['SOURCE_INCLUDES']) + pkgsExcludes.extend(env['BUILD_PACKAGES'][package]['SOURCE_EXCLUDES']) + + # make sure there weren't repeats between packages +# pkgsDirs = self.removeDuplicates(pkgsDirs) # this depends on order + pkgsTargets = self.removeDuplicates(pkgsTargets) + pkgsIncludes = self.removeDuplicates(pkgsIncludes) + pkgsExcludes = self.removeDuplicates(pkgsExcludes) + + # add sub_dirs + self.__add_subdirs_withSource(filter(lambda x: exists(join(self.path.abspath(), x)), pkgsDirs)) + + # add targets + targets = self.targets.split(',') + targets.extend(pkgsTargets) + targets = self.removeDuplicates(targets) + self.targets = ','.join(targets) + + # deliver certain things in main directory regarless + if env['DELIVER_SOURCE'] is True: + for x in pkgsIncludes : + if os.path.isdir(join(self.path.abspath(), x)) : + self.copyTree(join(self.path.abspath(), x), join(env['PREFIX'], 'source', x), pkgsExcludes, env['PREFIX']) + else : + self.install_files(join(env['PREFIX'], 'source', os.path.split(x)[0]), x) + + def install_tgt(tsk, **modArgs): + # The main purpose this serves is to recursively copy all the wscript's + # involved when we have a wscript whose sole job is to install files + modArgs = dict((k.lower(), v) for k, v in modArgs.iteritems()) + if 'env' in modArgs: + env = modArgs['env'] + else: + variant = modArgs.get('variant', tsk.env['VARIANT'] or 'default') + env = tsk.all_envs[variant] + + features = 'install_tgt' + if env['install_source']: + targetsToAdd = modArgs.get('targets_to_add', []) + targetsToAdd = targetsToAdd + getWscriptTargets(tsk, env, tsk.path) + modArgs['targets_to_add'] = targetsToAdd + features += ' add_targets' + return tsk(features = features, **modArgs) + + def module(self, **modArgs): + """ + Builds a module, along with optional tests. + It makes assumptions, but most can be overridden by passing in args. + """ + bld = self + if 'env' in modArgs: + env = modArgs['env'] + else: + variant = modArgs.get('variant', bld.env['VARIANT'] or 'default') + env = bld.all_envs[variant] + + modArgs = dict((k.lower(), v) for k, v in modArgs.iteritems()) + + for func in self.module_hooks: + func(modArgs, env) + + lang = modArgs.get('lang', 'c++') + libExeType = {'c++':'cxx', 'c':'c'}.get(lang, 'cxx') + sourceExt = {'c++':'.cpp', 'c':'.c'}.get(lang, 'cxx') + if modArgs.get('nosuffix', False) : + libName = modArgs['name'] + else : + libName = '%s-%s' % (modArgs['name'], lang) + path = modArgs.get('path', + 'dir' in modArgs and bld.path.find_dir(modArgs['dir']) or bld.path) + + module_deps = map(lambda x: '%s-%s' % (x, lang), listify(modArgs.get('module_deps', ''))) + defines = self.__getDefines(env) + listify(modArgs.get('defines', '')) + uselib_local = module_deps + listify(modArgs.get('uselib_local', '')) + listify(modArgs.get('use','')) + uselib = listify(modArgs.get('uselib', '')) + ['CSTD', 'CRUN'] + targets_to_add = listify(modArgs.get('targets_to_add', '')) + includes = listify(modArgs.get('includes', 'include')) + exportIncludes = listify(modArgs.get('export_includes', 'include')) + libVersion = modArgs.get('version', None) + installPath = modArgs.get('install_path', None) + + # This specifies that we need to check if it is a USELIB or USELIB_LOCAL + # If MAKE_%% is defined, then it is local; otherwise, it's a uselib + # If we're doing a source installation and we built it locally, the + # source target already got added on as a dependency. If we didn't + # build it locally, we need to add the source target on here since + # in that case this module doesn't depend on a task associated with + # the external library. + uselibCheck = modArgs.get('uselib_check', None) + if uselibCheck: + for currentLib in listify(uselibCheck): + if ('MAKE_%s' % currentLib) in env: + uselib_local += [currentLib] + else: + uselib += [currentLib] + if env['install_source']: + sourceTarget = '%s_SOURCE_INSTALL' % currentLib + targets_to_add += [sourceTarget] + + # this specifies that we need to check if it is a USELIB or USELIB_LOCAL + # if MAKE_%% is defined, then it is local; otherwise, it's a uselib + uselibCheck = modArgs.pop('uselib_check', None) + if uselibCheck: + if ('MAKE_%s' % uselibCheck) in env: + uselib_local.append(uselibCheck) + else: + uselib.append(uselibCheck) + + if libVersion is not None and sys.platform != 'win32': + targetName = '%s.%s' % (libName, self.safeVersion(libVersion)) + else: + targetName = libName + + allSourceExt = listify(modArgs.get('source_ext', '')) + [sourceExt] + sourcedirs = listify(modArgs.get('source_dir', modArgs.get('sourcedir', 'source'))) + glob_patterns = [] + for dir in sourcedirs: + for ext in allSourceExt: + glob_patterns.append(join(dir, '*%s' % ext)) + + #build the lib + lib = bld(features='%s %s%s add_targets includes'% (libExeType, libExeType, env['LIB_TYPE'] or 'stlib'), includes=includes, + target=targetName, name=libName, export_includes=exportIncludes, + use=uselib_local, uselib=uselib, env=env.derive(), + defines=defines, path=path, + source=path.ant_glob(glob_patterns), targets_to_add=targets_to_add) + lib.source = filter(partial(lambda x, t: basename(str(t)) not in x, modArgs.get('source_filter', '').split()), lib.source) + + if env['install_libs']: + lib.install_path = installPath or env['install_libdir'] + + if not lib.source: + lib.features = 'add_targets includes' + + pattern = env['%s%s_PATTERN' % (libExeType, env['LIB_TYPE'] or 'stlib')] + if libVersion is not None and sys.platform != 'win32' and Options.options.symlinks and env['install_libs'] and lib.source: + symlinkLoc = '%s/%s' % (lib.install_path, pattern % libName) + lib.targets_to_add.append(bld(features='symlink_as_tgt', dest=symlinkLoc, src=pattern % lib.target, name='%s-symlink' % libName)) + + if env['install_headers']: + lib.targets_to_add.append(bld(features='install_tgt', pattern='**/*', + dir=path.make_node('include'), + install_path=env['install_includedir'])) + + addSourceTargets(bld, env, path, lib) + + testNode = path.make_node('tests') + if os.path.exists(testNode.abspath()) and not Options.options.libs_only: + test_deps = listify(modArgs.get('test_deps', modArgs.get('module_deps', ''))) + + test_deps.append(modArgs['name']) + + test_deps = map(lambda x: '%s-%s' % (x, lang), test_deps + listify(modArgs.get('test_uselib_local', '')) + listify(modArgs.get('test_use',''))) + + for test in testNode.ant_glob('*%s' % sourceExt): + if str(test) not in listify(modArgs.get('test_filter', '')): + testName = splitext(str(test))[0] + self.program(env=env.derive(), name=testName, target=testName, source=str(test), + use=test_deps, + uselib=modArgs.get('test_uselib', uselib), + lang=lang, path=testNode, includes=includes, defines=defines, + install_path='${PREFIX}/tests/%s' % modArgs['name']) + + testNode = path.make_node('unittests') + if os.path.exists(testNode.abspath()) and not Options.options.libs_only: + test_deps = listify(modArgs.get('unittest_deps', modArgs.get('module_deps', ''))) + test_uselib = listify(modArgs.get('unittest_uselib', uselib)) + + test_deps.append(modArgs['name']) + + if 'INCLUDES_UNITTEST' in env: + includes.append(env['INCLUDES_UNITTEST'][0]) + + test_deps = map(lambda x: '%s-%s' % (x, lang), test_deps + listify(modArgs.get('test_uselib_local', '')) + listify(modArgs.get('test_use',''))) + + sourceExt = {'c++':'.cpp', 'c':'.c'}.get(lang, 'cxx') + tests = [] + for test in testNode.ant_glob('*%s' % sourceExt): + if str(test) not in listify(modArgs.get('unittest_filter', '')): + testName = splitext(str(test))[0] + exe = self(features='%s %sprogram' % (libExeType, libExeType), + env=env.derive(), name=testName, target=testName, source=str(test), use=test_deps, + uselib = modArgs.get('unittest_uselib', modArgs.get('uselib', '')), + lang=lang, path=testNode, defines=defines, + includes=includes, + install_path='${PREFIX}/unittests/%s' % modArgs['name']) + if Options.options.unittests or Options.options.all_tests: + exe.features += ' test' + + tests.append(testName) + + # add a post-build hook to run the unit tests + # I use partial so I can pass arguments to a post build hook + #if Options.options.unittests: + # bld.add_post_fun(partial(CPPBuildContext.runUnitTests, + # tests=tests, + # path=self.getBuildDir(testNode))) + + confDir = path.make_node('conf') + if exists(confDir.abspath()): + lib.targets_to_add.append( + bld(features='install_tgt', dir=confDir, pattern='**', + install_path='${PREFIX}/share/%s/conf' % modArgs['name'], + copy_to_source_dir=True)) + + return env + + + def plugin(self, **modArgs): + """ + Builds a plugin (.so) and sets the install path based on the type of + plugin (via the plugin kwarg). + """ + bld = self + if 'env' in modArgs: + env = modArgs['env'].derive() + else: + variant = modArgs.get('variant', bld.env['VARIANT'] or 'default') + env = bld.all_envs[variant].derive() + + modArgs = dict((k.lower(), v) for k, v in modArgs.iteritems()) + lang = modArgs.get('lang', 'c++') + libExeType = {'c++':'cxx', 'c':'c'}.get(lang, 'cxx') + libName = modArgs.get('libname', '%s-%s' % (modArgs['name'], lang)) + targetName = modArgs.get('targetname', libName) + plugin = modArgs.get('plugin', '') + path = modArgs.get('path', + 'dir' in modArgs and bld.path.find_dir(modArgs['dir']) or bld.path) + + module_deps = map(lambda x: '%s-%s' % (x, lang), listify(modArgs.get('module_deps', ''))) + defines = self.__getDefines(env) + listify(modArgs.get('defines', '')) + ['PLUGIN_MODULE_EXPORTS'] + uselib_local = module_deps + listify(modArgs.get('uselib_local', '')) + listify(modArgs.get('use','')) + uselib = listify(modArgs.get('uselib', '')) + ['CSTD', 'CRUN'] + targets_to_add = listify(modArgs.get('targets_to_add', '')) + includes = listify(modArgs.get('includes', 'include')) + exportIncludes = listify(modArgs.get('export_includes', 'include')) + source = listify(modArgs.get('source', '')) or None + removePluginPrefix = modArgs.get('removepluginprefix', False) + + # This is so that on Unix we name the plugins without the 'lib' prefix + if removePluginPrefix: + if env['cshlib_PATTERN'].startswith('lib'): + env['cshlib_PATTERN'] = env['cshlib_PATTERN'][3:] + if env['cxxshlib_PATTERN'].startswith('lib'): + env['cxxshlib_PATTERN'] = env['cxxshlib_PATTERN'][3:] + + lib = bld(features='%s %sshlib add_targets no_implib' % (libExeType, libExeType), + target=libName, name=targetName, source=source, + includes=includes, export_includes=exportIncludes, + use=uselib_local, uselib=uselib, env=env.derive(), + defines=defines, path=path, targets_to_add=targets_to_add, + install_path=join(env['install_sharedir'], plugin, 'plugins')) + + sourceExt = {'c++':'.cpp', 'c':'.c'}.get(lang, 'cxx') + allSourceExt = listify(modArgs.get('source_ext', '')) + [sourceExt] + sourcedirs = listify(modArgs.get('source_dir', modArgs.get('sourcedir', 'source'))) + glob_patterns = [] + for dir in sourcedirs: + for ext in allSourceExt: + glob_patterns.append(join(dir, '*%s' % ext)) + + if not source: + lib.source = path.ant_glob(glob_patterns) + lib.source = filter(partial(lambda x, t: basename(str(t)) not in x, modArgs.get('source_filter', '').split()), lib.source) + if env['install_headers']: + lib.targets_to_add.append(bld(features='install_tgt', pattern='**/*', + dir=path.make_node('include'), + install_path=env['install_includedir'])) + + addSourceTargets(self, env, path, lib) + + confDir = path.make_node('conf') + if exists(confDir.abspath()): + lib.targets_to_add.append( + bld(features='install_tgt', dir=confDir, pattern='**', + install_path='${PREFIX}/share/%s/conf' % plugin, + copy_to_source_dir=True)) + + pluginsTarget = '%s-plugins' % plugin + try: + bld.get_tgen_by_name(pluginsTarget).targets_to_add.append(libName) + except: + bld(target=pluginsTarget, + features='add_targets', targets_to_add=[libName]) + + def program_helper(self, **modArgs): + """ + Builds a program (exe) + """ + bld = self + if 'env' in modArgs: + env = modArgs['env'] + else: + variant = modArgs.get('variant', bld.env['VARIANT'] or 'default') + env = bld.all_envs[variant] + + modArgs = dict((k.lower(), v) for k, v in modArgs.iteritems()) + lang = modArgs.get('lang', 'c++') + libExeType = {'c++':'cxx', 'c':'c'}.get(lang, 'cxx') + progName = modArgs['name'] + path = modArgs.get('path', + 'dir' in modArgs and bld.path.find_dir(modArgs['dir']) or bld.path) + + module_deps = map(lambda x: '%s-%s' % (x, lang), listify(modArgs.get('module_deps', ''))) + defines = self.__getDefines(env) + listify(modArgs.get('defines', '')) + uselib_local = module_deps + listify(modArgs.get('uselib_local', '')) + listify(modArgs.get('use','')) + uselib = listify(modArgs.get('uselib', '')) + ['CSTD', 'CRUN'] + targets_to_add = listify(modArgs.get('targets_to_add', '')) + includes = listify(modArgs.get('includes', 'include')) + source = listify(modArgs.get('source', '')) or None + install_path = modArgs.get('install_path', env['install_bindir']) + + if not source: + source = bld.path.make_node(modArgs.get('source_dir', modArgs.get('sourcedir', 'source'))).ant_glob('*.c*', excl=modArgs.get('source_filter', '')) + + exe = bld.program(features = 'add_targets', + source=source, name=progName, + includes=includes, defines=defines, + use=uselib_local, uselib=uselib, + env=env.derive(), target=progName, path=path, + install_path=install_path, + targets_to_add=targets_to_add) + + addSourceTargets(bld, env, path, exe) + + return exe + + + def getBuildDir(self, path=None): + """ + Returns the build dir, relative to where you currently are (bld.path) + """ + if path is None: + path = self.path + return path.find_or_declare('.').abspath() + + def mexify(self, **modArgs): + """ + Utility for compiling a mex file (with mexFunction) to a mex shared lib + """ + bld = self + if 'env' in modArgs: + env = modArgs['env'] + else: + variant = modArgs.get('variant', bld.env['VARIANT'] or 'default') + env = bld.all_envs[variant] + + if self.is_defined('HAVE_MEX_H'): + + modArgs = dict((k.lower(), v) for k, v in modArgs.iteritems()) + lang = modArgs.get('lang', 'c++') + libExeType = {'c++':'cxx', 'c':'c'}.get(lang, 'cxx') + path = modArgs.get('path', + 'dir' in modArgs and bld.path.find_dir(modArgs['dir']) or bld.path) + + #override the shlib pattern + env = env.derive() + shlib_pattern = '%sshlib_PATTERN' % libExeType + if env[shlib_pattern].startswith('lib'): + env[shlib_pattern] = env[shlib_pattern][3:] + env[shlib_pattern] = splitext(env[shlib_pattern])[0] + env['MEX_EXT'] + + module_deps = map(lambda x: '%s-%s' % (x, lang), listify(modArgs.get('module_deps', ''))) + defines = self.__getDefines(env) + listify(modArgs.get('defines', '')) + uselib_local = module_deps + listify(modArgs.get('uselib_local', '')) + listify(modArgs.get('use','')) + uselib = listify(modArgs.get('uselib', '')) + ['CSTD', 'CRUN', 'MEX'] + includes = listify(modArgs.get('includes', 'include')) + installPath = modArgs.get('install_path', None) + source = modArgs.get('source', None) + name = modArgs.get('name', None) + targetName = modArgs.get('target', None) + + if source: + name = splitext(split(source)[1])[0] + + mex = bld(features='%s %sshlib'%(libExeType, libExeType), target=targetName or name, + name=name, use=uselib_local, + uselib=uselib, env=env.derive(), defines=defines, + path=path, source=source, includes=includes, + install_path=installPath or '${PREFIX}/mex') + if not source: + mex.source = path.ant_glob(modArgs.get('source_dir', modArgs.get('sourcedir', 'source')) + '/*') + mex.source = filter(partial(lambda x, t: basename(str(t)) not in x, modArgs.get('source_filter', '').split()), lib.source) + pattern = env['%s_PATTERN' % (env['LIB_TYPE'] or 'staticlib')] + + + +class GlobDirectoryWalker: + """ recursively walk a directory, matching filenames """ + def __init__(self, directory, patterns=["*"]): + self.stack = [directory] + self.patterns = patterns + self.files = [] + self.index = 0 + + def __iter__(self): + return self.next() + + def next(self): + while True: + try: + file = self.files[self.index] + self.index = self.index + 1 + except IndexError: + # pop next directory from stack + if len(self.stack) == 0: + raise StopIteration + self.directory = self.stack.pop() + if isdir(self.directory): + self.files = os.listdir(self.directory) + else: + self.files, self.directory = [self.directory], '' + self.index = 0 + else: + # got a filename + fullname = join(self.directory, file) + if isdir(fullname):# and not os.path.islink(fullname): + self.stack.append(fullname) + for p in self.patterns: + if fnmatch.fnmatch(file, p): + yield fullname + +def recursiveGlob(directory, patterns=["*"]): + return GlobDirectoryWalker(directory, patterns) + + +def getPlatform(pwd=None, default=None): + """ returns the platform name """ + platform = default or sys.platform + + if platform != 'win32': + if not pwd: + pwd = os.getcwd() + + locs = recursiveGlob(pwd, patterns=['config.guess']) + for loc in locs: + if not exists(loc): continue + try: + out = os.popen('chmod +x %s' % loc) + out.close() + except:{} + try: + out = os.popen(loc, 'r') + platform = out.readline() + platform = platform.strip('\n') + out.close() + except:{} + else: + break + return platform + + + +import zipfile +def unzipper(inFile, outDir): + if not outDir.endswith(':') and not exists(outDir): + os.mkdir(outDir) + + zf = zipfile.ZipFile(inFile) + + dirs = filter(lambda x: x.endswith('/'), zf.namelist()) + dirs.sort() + + for d in filter(lambda x: not exists(x), + map(lambda x: join(outDir, x), dirs)): + os.mkdir(d) + + for i, name in enumerate(filter(lambda x: not x.endswith('/'), zf.namelist())): + outFile = open(join(outDir, name), 'wb') + outFile.write(zf.read(name)) + outFile.flush() + outFile.close() + +def options(opt): + opt.load('compiler_cc') + opt.load('compiler_cxx') + opt.load('waf_unit_test') + + if sys.version_info >= (2,5,0): + opt.load('msvs') + + if Options.platform == 'win32': + opt.load('msvc') + opt.add_option('--with-crt', action='store', choices=['MD', 'MT'], + dest='crt', default='MD', help='Specify Windows CRT library - MT or MD (default)') + + opt.add_option('--packages', action='store', dest='packages', + help='Target packages to build (common-separated list)') + opt.add_option('--dist-source', action='store_true', dest='dist_source', default=False, + help='Distribute source into the installation area (for delivering source)') + opt.add_option('--disable-warnings', action='store_false', dest='warnings', + default=True, help='Disable warnings') + opt.add_option('--warnings-as-errors', action='store_true', dest='warningsAsErrors', + default=False, help='Treat compiler warnings as errors') + opt.add_option('--enable-debugging', action='store_true', dest='debugging', + help='Enable debugging') + #TODO - get rid of enable64 - it's useless now + opt.add_option('--enable-64bit', action='store_true', dest='enable64', + help='Enable 64bit builds') + opt.add_option('--enable-32bit', action='store_true', dest='enable32', + help='Enable 32bit builds') + opt.add_option('--with-cflags', action='store', nargs=1, dest='cflags', + help='Set non-standard CFLAGS', metavar='FLAGS') + opt.add_option('--with-cxxflags', action='store', nargs=1, dest='cxxflags', + help='Set non-standard CXXFLAGS (C++)', metavar='FLAGS') + opt.add_option('--with-linkflags', action='store', nargs=1, dest='linkflags', + help='Set non-standard LINKFLAGS (C/C++)', metavar='FLAGS') + opt.add_option('--with-defs', action='store', nargs=1, dest='_defs', + help='Use DEFS as macro definitions', metavar='DEFS') + opt.add_option('--with-optz', action='store', + choices=['med', 'fast', 'fastest'], + default='fastest', metavar='OPTZ', + help='Specify the optimization level for optimized/release builds') + opt.add_option('--libs-only', action='store_true', dest='libs_only', + help='Only build the libs (skip building the tests, etc.)') + opt.add_option('--shared', action='store_true', dest='shared_libs', + help='Build all libs as shared libs') + opt.add_option('--disable-symlinks', action='store_false', dest='symlinks', + default=True, help='Disable creating symlinks for libs') + opt.add_option('--unittests', action='store_true', dest='unittests', + help='Build-time option to run unit tests after the build has completed') + opt.add_option('--no-headers', action='store_false', dest='install_headers', + default=True, help='Don\'t install module headers') + opt.add_option('--no-libs', action='store_false', dest='install_libs', + default=True, help='Don\'t install module libraries') + opt.add_option('--includedir', action='store', nargs=1, dest='includedir', + help='Override installation include directory') + opt.add_option('--libdir', action='store', nargs=1, dest='libdir', + help='Override installation lib directory') + opt.add_option('--bindir', action='store', nargs=1, dest='bindir', + help='Override installation bin directory') + opt.add_option('--sharedir', action='store', nargs=1, dest='sharedir', + help='Override installation share directory') + opt.add_option('--install-source', action='store_true', dest='install_source', default=False, + help='Distribute source into the installation area (for delivering source)') + + +types_str = ''' +#include +int isBigEndian() +{ + long one = 1; + return !(*((char *)(&one))); +} +int main() +{ + if (isBigEndian()) printf("bigendian=True\\n"); + else printf("bigendian=False\\n"); + printf("sizeof_int=%d\\n", sizeof(int)); + printf("sizeof_short=%d\\n", sizeof(short)); + printf("sizeof_long=%d\\n", sizeof(long)); + printf("sizeof_long_long=%d\\n", sizeof(long long)); + printf("sizeof_float=%d\\n", sizeof(float)); + printf("sizeof_double=%d\\n", sizeof(double)); + printf("sizeof_size_t=%d\\n", sizeof(size_t)); + printf("sizeof_wchar_t=%d\\n", sizeof(wchar_t)); + return 0; +} +''' + +def configure(self): + + if self.env['DETECTED_BUILD_PY']: + return + + sys_platform = getPlatform(default=Options.platform) + appleRegex = r'i.86-apple-.*' + linuxRegex = r'.*-.*-linux-.*|i686-pc-.*|linux' + solarisRegex = r'sparc-sun.*|i.86-pc-solaris.*|sunos' + winRegex = r'win32' + + # build packages is a map of maps + self.env['BUILD_PACKAGES'] = {} + + # store in the environment whether the user wants to + # deliver source into the installation area -- + # this can also be a build time argument if placed in + # the top level wscript + self.env['DELIVER_SOURCE'] = Options.options.dist_source + + self.msg('Platform', sys_platform, color='GREEN') + + # Dirty fix to get around libpath problems.. + if re.match(winRegex, sys_platform): + real_cmd_and_log = self.cmd_and_log + def wrap_cmd_and_log(*k, **kw): + sout = real_cmd_and_log(*k, **kw) + if sout: + lines=sout.splitlines() + if not lines[0]:lines=lines[1:] + for line in lines[1:]: + if line.startswith('LIB='): + for i in line[4:].split(';'): + if i: + if not os.path.exists(i): + self.fatal('libpath does not exist') + return sout + self.cmd_and_log = wrap_cmd_and_log + + # If we're in the Windows SDK or VS command prompt, having these set can mess things up. + env_lib = self.environ.get('LIB', None) + if 'LIB' in self.environ: del self.environ['LIB'] + env_cl = os.environ.get('CL', None) + if 'CL' in os.environ: del os.environ['CL'] + + if Options.options.enable64 or ('64' in platform.machine() and not Options.options.enable32): + # x64 is the native 64-bit compiler, so prefer this one. If we + # just have VS Express though, we won't have it, so fall back on + # x86_amd64 - this is a 32-bit compiler that cross-compiles to + # 64-bit. VS 2012 Express ships with this one, and earlier VS + # Express versions can get this via the Windows SDK. + self.env['MSVC_TARGETS'] = ['x64', 'x86_amd64'] + + # Look for 32-bit msvc if we don't find 64-bit. + if not Options.options.enable64: + self.options.check_c_compiler = self.options.check_cxx_compiler = 'msvc' + try: + self.load('compiler_c') + except self.errors.ConfigurationError: + self.env['MSVC_TARGETS'] = None + self.tool_cache.remove(('msvc',id(self.env),None)) + self.tool_cache.remove(('compiler_c',id(self.env),None)) + self.msg('Checking for \'msvc\'', 'Warning: cound not find x64 msvc, looking for others', color='RED') + else: + self.env['MSVC_TARGETS'] = ['x86'] + + self.load('compiler_c') + self.load('compiler_cxx') + self.load('waf_unit_test') + + # Reset cmd_and_log + if re.match(winRegex, sys_platform): + self.cmd_and_log = real_cmd_and_log + if env_lib is not None: self.environ['LIB'] = env_lib + if env_cl is not None: os.environ['CL'] = env_cl + + cxxCompiler = self.env["COMPILER_CXX"] + ccCompiler = self.env["COMPILER_CC"] + + if ccCompiler == 'msvc': + cxxCompiler = ccCompiler + + if not cxxCompiler or not ccCompiler: + self.fatal('Unable to find C/C++ compiler') + + #Look for a ton of headers + self.check_cc(header_name="inttypes.h", mandatory=False) + self.check_cc(header_name="unistd.h", mandatory=False) + self.check_cc(header_name="getopt.h", mandatory=False) + self.check_cc(header_name="malloc.h", mandatory=False) + self.check_cc(header_name="sys/time.h", mandatory=False) + self.check_cc(header_name="limits.h", mandatory=False) + self.check_cc(header_name="dlfcn.h", mandatory=False) + self.check_cc(header_name="fcntl.h", mandatory=False) + self.check_cc(header_name="check.h", mandatory=False) + self.check_cc(header_name="memory.h", mandatory=False) + self.check_cc(header_name="string.h", mandatory=False) + self.check_cc(header_name="strings.h", mandatory=False) + self.check_cc(header_name="stdbool.h", mandatory=False) + self.check_cc(header_name="stdlib.h", mandatory=False) + self.check_cc(header_name="stddef.h", mandatory=False) + self.check_cc(function_name='localtime_r', header_name="time.h", mandatory=False) + self.check_cc(function_name='gmtime_r', header_name="time.h", mandatory=False) + self.check_cc(function_name='mmap', header_name="sys/mman.h", mandatory=False) + self.check_cc(function_name='memmove', header_name="string.h", mandatory=False) + self.check_cc(function_name='memset', header_name="string.h", mandatory=False) + self.check_cc(function_name='strerror', header_name="string.h", mandatory=False) + self.check_cc(function_name='bcopy', header_name="strings.h", mandatory=False) + self.check_cc(type_name='ssize_t', header_name='sys/types.h', mandatory=False) + self.check_cc(fragment='int main(){const int i = 0; return 0;}', + define_name='HAVE_CONST', msg='Checking for const keyword', mandatory=False) + self.check_cc(fragment='int main(){unsigned short; return 0;}', + define_name='HAVE_UNSIGNED_SHORT', msg='Checking for unsigned short', mandatory=False) + self.check_cc(fragment='int main(){unsigned char i; return 0;}', + define_name='HAVE_UNSIGNED_CHAR', msg='Checking for unsigned char', mandatory=False) + self.check_cc(lib="m", mandatory=False, uselib_store='MATH') + self.check_cc(lib="rt", mandatory=False, uselib_store='RT') + self.check_cc(lib="sqrt", mandatory=False, uselib_store='SQRT') + self.check_cc(function_name='erf', header_name="math.h", use = "MATH", mandatory=False) + self.check_cc(function_name='erff', header_name="math.h", use = "MATH", mandatory=False) + self.check_cc(function_name='setenv', header_name="stdlib.h", mandatory=False) + + self.check_cc(function_name='gettimeofday', header_name='sys/time.h', mandatory=False) + if self.check_cc(lib='rt', function_name='clock_gettime', header_name='time.h', mandatory=False): + self.env.DEFINES.append('USE_CLOCK_GETTIME') + self.check_cc(function_name='BSDgettimeofday', header_name='sys/time.h', mandatory=False) + self.check_cc(function_name='gethrtime', header_name='sys/time.h', mandatory=False) + self.check_cc(function_name='getpagesize', header_name='unistd.h', mandatory=False) + self.check_cc(function_name='getopt', header_name='unistd.h', mandatory=False) + self.check_cc(function_name='getopt_long', header_name='getopt.h', mandatory=False) + + self.check_cc(fragment='#include \nint main(){if (!isnan(3.14159)) isnan(2.7183);}', + define_name='HAVE_ISNAN', msg='Checking for function isnan', + errmsg='not found', mandatory=False) + + # Check for hrtime_t data type; some systems (AIX) seem to have + # a function called gethrtime but no hrtime_t! + frag = ''' + #ifdef HAVE_SYS_TIME_H + #include + int main(){hrtime_t foobar;} + #endif + ''' + self.check_cc(fragment=frag, define_name='HAVE_HRTIME_T', + msg='Checking for type hrtime_t', errmsg='not found', mandatory=False) + + + #find out the size of some types, etc. + # TODO: This is not using the 32 vs. 64 bit linker flags, so if you're + # building with --enable-32bit on 64 bit Linux, sizeof(size_t) will + # erroneously be 8 here. + output = self.check(fragment=types_str, execute=1, msg='Checking system type sizes', define_ret=True) + t = Utils.str_to_dict(output or '') + for k, v in t.iteritems(): + try: + v = int(v) + except: + v = v.strip() + if v == 'True': + v = True + elif v == 'False': + v = False + #v = eval(v) + self.msg(k.replace('_', ' ', 1), str(v)) + self.define(k.upper(), v) + + env = self.env + env['PLATFORM'] = sys_platform + + env['LIB_TYPE'] = Options.options.shared_libs and 'shlib' or 'stlib' + + env['install_headers'] = Options.options.install_headers + env['install_libs'] = Options.options.install_libs + env['install_source'] = Options.options.install_source + + env['install_includedir'] = Options.options.includedir if Options.options.includedir else join(Options.options.prefix, 'include') + env['install_libdir'] = Options.options.libdir if Options.options.libdir else join(Options.options.prefix, 'lib') + env['install_bindir'] = Options.options.bindir if Options.options.bindir else join(Options.options.prefix, 'bin') + env['install_sharedir'] = Options.options.sharedir if Options.options.sharedir else join(Options.options.prefix, 'share') + + if Options.options.cxxflags: + env.append_unique('CXXFLAGS', Options.options.cxxflags.split()) + if Options.options.cflags: + env.append_unique('CFLAGS', Options.options.cflags.split()) + if Options.options.linkflags: + env.append_unique('LINKFLAGS', Options.options.linkflags.split()) + if Options.options._defs: + env.append_unique('DEFINES', Options.options._defs.split(',')) + + config = {'cxx':{}, 'cc':{}} + + #apple + if re.match(appleRegex, sys_platform): + env.append_value('LIB_DL', 'dl') + env.append_value('LIB_NSL', 'nsl') + env.append_value('LIB_THREAD', 'pthread') + env.append_value('DEFINES_THREAD', '_REENTRANT') + self.check_cc(lib='pthread', mandatory=True) + + config['cxx']['debug'] = '-g' + config['cxx']['warn'] = '-Wall' + config['cxx']['verbose'] = '-v' + config['cxx']['64'] = '-m64' + config['cxx']['32'] = '-m32' + config['cxx']['optz_med'] = '-O1' + config['cxx']['optz_fast'] = '-O2' + config['cxx']['optz_fastest'] = '-O3' + + #env.append_value('LINKFLAGS', '-fPIC -dynamiclib'.split()) + env.append_value('LINKFLAGS', '-fPIC'.split()) + env.append_value('CXXFLAGS', '-fPIC') + + config['cc']['debug'] = config['cxx']['debug'] + config['cc']['warn'] = config['cxx']['warn'] + config['cc']['verbose'] = config['cxx']['verbose'] + config['cc']['64'] = config['cxx']['64'] + config['cc']['optz_med'] = config['cxx']['optz_med'] + config['cc']['optz_fast'] = config['cxx']['optz_fast'] + config['cc']['optz_fastest'] = config['cxx']['optz_fastest'] + + env.append_value('DEFINES', '_FILE_OFFSET_BITS=64 _LARGEFILE_SOURCE __POSIX'.split()) + env.append_value('CFLAGS', '-fPIC -dynamiclib'.split()) + + #linux + elif re.match(linuxRegex, sys_platform): + env.append_value('LIB_DL', 'dl') + env.append_value('LIB_NSL', 'nsl') + env.append_value('LIB_THREAD', 'pthread') + env.append_value('DEFINES_THREAD', '_REENTRANT') + env.append_value('LIB_MATH', 'm') + + self.check_cc(lib='pthread', mandatory=True) + + warningFlags = '-Wall' + if Options.options.warningsAsErrors: + warningFlags += ' -Wfatal-errors' + + if cxxCompiler == 'g++': + config['cxx']['debug'] = '-g' + config['cxx']['warn'] = warningFlags.split() + config['cxx']['verbose'] = '-v' + config['cxx']['64'] = '-m64' + config['cxx']['32'] = '-m32' + config['cxx']['linkflags_64'] = '-m64' + config['cxx']['linkflags_32'] = '-m32' + config['cxx']['optz_med'] = '-O1' + config['cxx']['optz_fast'] = '-O2' + config['cxx']['optz_fastest'] = '-O3' + + env.append_value('CXXFLAGS', '-fPIC') + + # DEFINES and LINKFLAGS will apply to both gcc and g++ + env.append_value('DEFINES', '_FILE_OFFSET_BITS=64 _LARGEFILE_SOURCE __POSIX'.split()) + env.append_value('LINKFLAGS', '-Wl,-E -fPIC'.split()) + + if ccCompiler == 'gcc': + config['cc']['debug'] = '-g' + config['cc']['warn'] = warningFlags.split() + config['cc']['verbose'] = '-v' + config['cc']['64'] = '-m64' + config['cc']['32'] = '-m32' + config['cc']['linkflags_64'] = '-m64' + config['cc']['linkflags_32'] = '-m32' + config['cc']['optz_med'] = '-O1' + config['cc']['optz_fast'] = '-O2' + config['cc']['optz_fastest'] = '-O3' + + env.append_value('CFLAGS', '-fPIC'.split()) + + #Solaris + elif re.match(solarisRegex, sys_platform): + env.append_value('LIB_DL', 'dl') + env.append_value('LIB_NSL', 'nsl') + env.append_value('LIB_SOCKET', 'socket') + env.append_value('LIB_THREAD', 'thread') + env.append_value('LIB_MATH', 'm') + env.append_value('LIB_CRUN', 'Crun') + env.append_value('LIB_CSTD', 'Cstd') + self.check_cc(lib='thread', mandatory=True) + self.check_cc(header_name="atomic.h", mandatory=False) + + warningFlags = '' + if Options.options.warningsAsErrors: + warningFlags = '-errwarn=%all' + + if cxxCompiler == 'sunc++': + (bitFlag32, bitFlag64) = getSolarisFlags(env['CXX'][0]) + config['cxx']['debug'] = '-g' + config['cxx']['warn'] = warningFlags.split() + config['cxx']['nowarn'] = '-erroff=%all' + config['cxx']['verbose'] = '-v' + config['cxx']['64'] = bitFlag64 + config['cxx']['32'] = bitFlag32 + config['cxx']['linkflags_32'] = bitFlag32 + config['cxx']['linkflags_64'] = bitFlag64 + config['cxx']['optz_med'] = '-xO3' + config['cxx']['optz_fast'] = '-xO4' + config['cxx']['optz_fastest'] = '-xO5' + env['CXXFLAGS_cxxshlib'] = ['-KPIC', '-DPIC'] + + # DEFINES apply to both suncc and sunc++ + env.append_value('DEFINES', '_FILE_OFFSET_BITS=64 _LARGEFILE_SOURCE'.split()) + env.append_value('CXXFLAGS', '-KPIC -instances=global'.split()) + env.append_value('CXXFLAGS_THREAD', '-mt') + + if ccCompiler == 'suncc': + (bitFlag32, bitFlag64) = getSolarisFlags(env['CC'][0]) + config['cc']['debug'] = '-g' + config['cc']['warn'] = warningFlags.split() + config['cc']['nowarn'] = '-erroff=%all' + config['cc']['verbose'] = '-v' + config['cc']['64'] = bitFlag64 + config['cc']['linkflags_64'] = bitFlag64 + config['cc']['linkflags_32'] = bitFlag32 + config['cc']['32'] = bitFlag32 + config['cc']['optz_med'] = '-xO3' + config['cc']['optz_fast'] = '-xO4' + config['cc']['optz_fastest'] = '-xO5' + env['CFLAGS_cshlib'] = ['-KPIC', '-DPIC'] + + env.append_value('CFLAGS', '-KPIC'.split()) + env.append_value('CFLAGS_THREAD', '-mt') + + elif re.match(winRegex, sys_platform): + + env.append_value('LIB_RPC', 'rpcrt4') + env.append_value('LIB_SOCKET', 'Ws2_32') + + crtFlag = '/%s' % Options.options.crt + crtDebug = '%sd' % crtFlag + + # Sets the size of the stack (in bytes) + stackFlag = '/STACK:80000000' + + # Skipping warning 4290 about how VS doesn't implement exception + # specifications properly. + # Skipping warning 4512 about being unable to generate an assignment + # operator (since we often do this intentionally). + # For warnings, use /W4 because /Wall + # gives us tons of warnings in the VS headers themselves + warningFlags = '/W4 /wd4290 /wd4512' + if Options.options.warningsAsErrors: + warningFlags += ' /WX' + + vars = {} + vars['debug'] = ['/Zi', crtDebug] + vars['warn'] = warningFlags.split() + vars['nowarn'] = '/w' + vars['verbose'] = '' + vars['optz_med'] = ['-O2', crtFlag] + vars['optz_fast'] = ['-O2', crtFlag] + vars['optz_fastest'] = ['-Ox', crtFlag] + # The MACHINE flag is is probably not actually necessary + # The linker should be able to infer it from the object files + # But doing this just to make sure we're really building 32/64 bit + # applications + vars['linkflags_32'] = [stackFlag, '/MACHINE:X86'] + vars['linkflags_64'] = [stackFlag, '/MACHINE:X64'] + + if Options.options.debugging: + # In order to generate a .pdb file, we need both the /Zi + # compilation flag and the /DEBUG linker flag + vars['linkflags_32'].append('/DEBUG') + vars['linkflags_64'].append('/DEBUG') + else: + # Forcing the linker to not link incrementally. Hoping this will + # avoid an intermittent race condition we're having where manifest + # generation fails. + # Incremental is implied with /DEBUG so no reason to bother + # setting it there + vars['linkflags_32'].append('/INCREMENTAL:NO') + vars['linkflags_64'].append('/INCREMENTAL:NO') + + # choose the runtime to link against + # [/MD /MDd /MT /MTd] + + config['cxx'].update(vars) + config['cc'].update(vars) + + defines = '_CRT_SECURE_NO_WARNINGS _SCL_SECURE_NO_WARNINGS _FILE_OFFSET_BITS=64 ' \ + '_LARGEFILE_SOURCE WIN32 _USE_MATH_DEFINES NOMINMAX WIN32_LEAN_AND_MEAN'.split() + flags = '/UUNICODE /U_UNICODE /EHs /GR'.split() + + env.append_value('DEFINES', defines) + env.append_value('DEFINES_THREAD', '_REENTRANT') + env.append_value('CXXFLAGS', flags) + env.append_value('CFLAGS', flags) + + else: + self.fatal('OS/platform currently unsupported: %s' % sys_platform) + + #CXX + if Options.options.warnings: + env.append_value('CXXFLAGS', config['cxx'].get('warn', '')) + env.append_value('CFLAGS', config['cc'].get('warn', '')) + else: + env.append_value('CXXFLAGS', config['cxx'].get('nowarn', '')) + env.append_value('CFLAGS', config['cc'].get('nowarn', '')) + if Options.options.verbose: + env.append_value('CXXFLAGS', config['cxx'].get('verbose', '')) + env.append_value('CFLAGS', config['cc'].get('verbose', '')) + + + # We don't really use variants right now, so keep the default environment linked to the variant. + variant = env + if Options.options.debugging: + variantName = '%s-debug' % sys_platform + variant.append_value('CXXFLAGS', config['cxx'].get('debug', '')) + variant.append_value('CFLAGS', config['cc'].get('debug', '')) + else: + variantName = '%s-release' % sys_platform + optz = Options.options.with_optz + variant.append_value('CXXFLAGS', config['cxx'].get('optz_%s' % optz, '')) + variant.append_value('CFLAGS', config['cc'].get('optz_%s' % optz, '')) + + # Check if the system is 64-bit capable + if re.match(winRegex, sys_platform): + # For Windows, this is a function of what VS compiler we ended up + # finding above (regardless of if we asked for 32 vs. 64 bit on the + # configure line) + frag64 = ''' +#include +int main() { +#ifdef _WIN64 + printf("1"); +#else + printf("0"); +#endif + return 0; } +''' + output = self.check(fragment=frag64, define_ret=True, + execute=1, msg='Checking for 64-bit system') + is64Bit = bool(int(output)) + elif Options.options.enable32 or not '64' in config['cxx']: + is64Bit = False + else: + is64Bit = self.check_cxx(cxxflags=config['cxx']['64'], + linkflags=config['cc'].get('linkflags_64', ''), + mandatory=False) and \ + self.check_cc(cflags=config['cc']['64'], + linkflags=config['cc'].get('linkflags_64', ''), + mandatory=False) + self.msg('System size', '64-bit' if is64Bit else '32-bit') + + if is64Bit: + if re.match(winRegex, sys_platform): + variantName = variantName.replace('32', '64') + else: + variantName = '%s-64' % variantName + variant.append_value('CXXFLAGS', config['cxx'].get('64', '')) + variant.append_value('CFLAGS', config['cc'].get('64', '')) + variant.append_value('LINKFLAGS', config['cc'].get('linkflags_64', '')) + else: + variant.append_value('CXXFLAGS', config['cxx'].get('32', '')) + variant.append_value('CFLAGS', config['cc'].get('32', '')) + variant.append_value('LINKFLAGS', config['cc'].get('linkflags_32', '')) + + env['IS64BIT'] = is64Bit + self.all_envs[variantName] = variant + self.setenv(variantName) + + env['VARIANT'] = variant['VARIANT'] = variantName + + #flag that we already detected + self.env['DETECTED_BUILD_PY'] = True + +@task_gen +@feature('untar') +def untar(tsk): + untarDriver(tsk.path, tsk.fname) + +def untarFile(path, fname): + import tarfile + f = path.find_or_declare(fname) + tf = tarfile.open(f.abspath(), 'r') + p = path.abspath() + for x in tf: + tf.extract(x, p) + tf.close() + +@task_gen +@feature('unzip') +def unzip(tsk): + f = tsk.path.find_or_declare(tsk.fname) + unzipper(f.abspath(), tsk.path.abspath()) + +# Needed to install files when using --target +@task_gen +@feature('install_tgt') +def install_tgt(tsk): + if os.path.exists(tsk.dir.abspath()): + if not hasattr(tsk, 'copy_to_source_dir') or not tsk.env['install_source']: + tsk.copy_to_source_dir = False + if not hasattr(tsk, 'pattern'): + tsk.pattern = [] + if not hasattr(tsk, 'relative_trick'): + tsk.relative_trick = False + if isinstance(tsk.pattern, str): + tsk.pattern = [tsk.pattern] + for pattern in tsk.pattern: + for file in tsk.dir.ant_glob(pattern): + if tsk.relative_trick: + dest = tsk.install_path + else: + dest = os.path.join(tsk.install_path, file.parent.path_from(tsk.dir)) + inst = tsk.bld.install_files(dest, file, + relative_trick=tsk.relative_trick) + if inst and hasattr(tsk, 'chmod'): + inst.chmod = tsk.chmod + + if tsk.copy_to_source_dir: + dest = os.path.join('${PREFIX}', 'source') + inst2 = tsk.bld.install_files(dest, file, + relative_trick=True) + if inst2 and hasattr(tsk, 'chmod'): + inst2.chmod = tsk.chmod + if not hasattr(tsk, 'files'): + tsk.files = [] + if isinstance(tsk.files, str): + tsk.files = [tsk.files] + for file in tsk.files: + inst = tsk.bld.install_files(tsk.install_path, tsk.dir.make_node(file), + relative_trick=tsk.relative_trick) + if inst and hasattr(tsk, 'chmod'): + inst.chmod = tsk.chmod + + if tsk.copy_to_source_dir: + dest = os.path.join('${PREFIX}', 'source') + inst2 = tsk.bld.install_files(dest, tsk.dir.make_node(file), + relative_trick=True) + if inst2 and hasattr(tsk, 'chmod'): + inst2.chmod = tsk.chmod + +@task_gen +@feature('copytree_tgt') +def copytree_tgt(tsk): + dest = Utils.subst_vars(tsk.dest, tsk.bld.env) + shutil.rmtree(dest, True) + symlinks = False + ignore = None + if hasattr(tsk, 'symlinks'): + symlinks = tsk.symlinks + if hasattr(tsk, 'ignore'): + ignore = tsk.ignore + shutil.copytree(tsk.src, dest, symlinks, ignore) + +@task_gen +@feature('install_as_tgt') +def install_as_tgt(tsk): + tsk.bld.install_as(tsk.install_as, tsk.file, cwd=tsk.dir) + +@task_gen +@feature('symlink_as_tgt') +def symlink_as_tgt(tsk): + tsk.bld.symlink_as(tsk.dest, tsk.src) + +# Allows a target to specify additonal targets to be executed. +@task_gen +@feature('add_targets') +def add_targets(self): + if isinstance(self.targets_to_add, str): + self.targets_to_add = [self.targets_to_add] + for target in self.targets_to_add: + if isinstance(target, task_gen): + target.post() + else: + self.bld.get_tgen_by_name(target).post() + +# When building a DLL, don't install the implib. +@task_gen +@feature('no_implib') +@after('apply_implib') +def no_implib(tsk): + if getattr(tsk, 'implib_install_task', None): + tsk.implib_install_task.exec_task = Utils.nada + +@task_gen +@feature('m4subst') +def m4subst(tsk): + m4substFile(input=tsk.input, output=tsk.output, path=tsk.path, dict=tsk.dict, env=tsk.env, chmod=getattr(tsk, 'chmod', None)) + +def m4substFile(input, output, path, dict={}, env=None, chmod=None): + import re + #similar to the subst in misc.py - but outputs to the src directory + m4_re = re.compile('@(\w+)@', re.M) + + infile = join(path.abspath(), input) + outfile = join(path.abspath(), output) + + file = open(infile, 'r') + code = file.read() + file.close() + + # replace all % by %% to prevent errors by % signs in the input file while string formatting + code = code.replace('%', '%%') + + s = m4_re.sub(r'%(\1)s', code) + + if not dict: + names = m4_re.findall(code) + for i in names: + dict[i] = env.get_flat(i) or env.get_flat(i.upper()) + + file = open(outfile, 'w') + file.write(s % dict) + file.close() + if chmod: os.chmod(outfile, chmod) + +@task_gen +@feature('handleDefs') +def handleDefs(tsk): + handleDefsFile(input=tsk.input, output=tsk.output, path=tsk.path, defs=tsk.defs, chmod=getattr(tsk, 'chmod', None)) + +def handleDefsFile(input, output, path, defs, chmod=None): + import re + infile = join(path.abspath(), input) + outfile = join(path.abspath(), output) + + file = open(infile, 'r') + code = file.read() + file.close() + + for k in defs.keys(): + v = defs[k] + if v is None: + v = '' + code = re.sub(r'#undef %s(\n)' % k, r'#define %s %s\1' % (k,v), code) + code = re.sub(r'(#undef[^\n]*)(\n)', r'/* \1 */\2', code) + file = open(outfile, 'w') + file.write(code) + file.close() + if chmod: os.chmod(outfile, chmod) + +@task_gen +@feature('makeHeader') +def makeHeader(tsk): + makeHeaderFile(output=tsk.output, path=tsk.path, defs=tsk.defs, + undefs=getattr(tsk, 'undefs', None), + chmod=getattr(tsk, 'chmod', None), + guard=getattr(tsk, 'guard', '__CONFIG_H__')) + +def makeHeaderFile(output, path, defs, undefs, chmod, guard): + outfile = join(path.abspath(), output) + dest = open(outfile, 'w') + dest.write('#ifndef %s\n#define %s\n\n' % (guard, guard)) + + for k in defs.keys(): + v = defs[k] + if v is None: + v = '' + dest.write('\n#ifndef %s\n#define %s %s\n#endif\n' % (k, k, v)) + + if undefs: + for u in undefs: + dest.write('\n#undef %s\n' % u) + + dest.write('\n#endif /* %s */\n' % guard) + dest.close() + if chmod: os.chmod(outfile, chmod) + +def getSolarisFlags(compilerName): + # Newer Solaris compilers use -m32 and -m64, so check to see if these flags exist + # If they don't, default to the old -xtarget flags + # TODO: Is there a cleaner way to do this with check_cc() instead? + bitFlag32 = '-xtarget=generic' + bitFlag64 = '-xtarget=generic64' + (out, err) = subprocess.Popen([compilerName, '-flags'], stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate() + + for line in out.split('\n'): + if re.match(r'-m32.*', line): + bitFlag32 = '-m32' + elif re.match(r'-m64.*', line): + bitFlag64 = '-m64' + + return (bitFlag32, bitFlag64) + +def getWscriptTargets(bld, env, path): + # Here we're taking a look at the current stack and adding on all the + # wscript's that got us to this point. + # The main additional difficulty here is that we can't just add these + # pathnames on because then the same file will be marked to be installed by + # multiple other targets (i.e. modules/c++/A and modules/c++/B will both + # try to install modules/c++/wscript). The way around this is to create + # a named target for all these wscript's based on their full pathname. + wscriptTargets = [] + for item in inspect.stack(): + pathname = item[1] + filename = os.path.basename(pathname) + if filename in ['wscript', 'waf']: + try: + # If this succeeds, somebody else has already made this target + # for us + wscriptTargets.append(bld.get_tgen_by_name(pathname)) + except: + # If we got here, no one has made the target yet, so we'll + # make it + # TODO: Not sure if there's a more efficient way to set + # dir below + dirname = os.path.dirname(pathname) + relpath = os.path.relpath(dirname, path.abspath()) + wscriptTargets.append(bld(features='install_tgt', + target=pathname, + pattern=['wscript', 'waf', '*.py', 'include/**/*', 'config.guess'], + dir=path.make_node(relpath), + install_path='${PREFIX}/source', + relative_trick=True)) + return wscriptTargets + +def addSourceTargets(bld, env, path, target): + if env['install_source']: + wscriptTargets = getWscriptTargets(bld, env, path) + + # We don't ever go into the project.cfg files, we call fromConfig on + # them from a wscript, so we have to call these out separately. + for targetName in path.ant_glob(['project.cfg']): + try: + wscriptTargets.append(bld.get_tgen_by_name(targetName)) + except: + wscriptTargets.append(bld(features='install_tgt', + target=targetName, + files = 'project.cfg', + pattern=['include/**/*'], + dir=path, install_path='${PREFIX}/source', + relative_trick=True)) + + source = [] + for file in target.source: + if type(file) is str: + source.append(file) + else: + source.append(file.path_from(path)) + + target.targets_to_add.append(bld(features='install_tgt', + files = source, + dir=path, install_path='${PREFIX}/source', + relative_trick=True)) + + target.targets_to_add += wscriptTargets + +class SwitchContext(Context.Context): + """ + Easily switch output directories without reconfiguration. + """ + cmd='switch' + def __init__(self,**kw): + super(SwitchContext,self).__init__(**kw) + def execute(self): + out_lock = self.path.make_node(Options.options.out).make_node(Options.lockfile) + root_lock = self.path.make_node(Options.lockfile) + if exists(out_lock.abspath()): + shutil.copy2(out_lock.abspath(), root_lock.abspath()) + else: + raise Errors.WafError('Out directory "%s" not configured.'%Options.options.out) + +class CPPBuildContext(BuildContext, CPPContext): + pass +class CPPListContext(ListContext, CPPContext): + pass +class CPPCleanContext(CleanContext, CPPContext): + pass +class CPPInstallContext(InstallContext, CPPContext): + pass + +class CPPMSVSGenContext(msvs_generator, CPPContext): + def __init__(self, **kw): + self.waf_command = 'python waf' + super(CPPMSVSGenContext, self).__init__(**kw) + +class CPPDumpEnvContext(dumpenv, CPPContext): + def __init__(self, **kw): + self.waf_command = 'python waf' + super(CPPDumpEnvContext, self).__init__(**kw) diff --git a/modules/build/config.guess b/modules/build/config.guess new file mode 100755 index 000000000..c93201a4d --- /dev/null +++ b/modules/build/config.guess @@ -0,0 +1,1501 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, +# Inc. + +timestamp='2006-11-08' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA +# 02110-1301, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + + +# Originally written by Per Bothner . +# Please send patches to . Submit a context +# diff and a properly formatted ChangeLog entry. +# +# This script attempts to guess a canonical system name similar to +# config.sub. If it succeeds, it prints the system name on stdout, and +# exits with 0. Otherwise, it exits with 1. +# +# The plan is that this can be called by configure scripts if you +# don't specify an explicit build system type. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 +Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +trap 'exit 1' 1 2 15 + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +set_cc_for_build=' +trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; +trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; +: ${TMPDIR=/tmp} ; + { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; +dummy=$tmp/dummy ; +tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; +case $CC_FOR_BUILD,$HOST_CC,$CC in + ,,) echo "int x;" > $dummy.c ; + for c in cc gcc c89 c99 ; do + if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then + CC_FOR_BUILD="$c"; break ; + fi ; + done ; + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found ; + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; +esac ; set_cc_for_build= ;' + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + sysctl="sysctl -n hw.machine_arch" + UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || echo unknown)` + case "${UNAME_MACHINE_ARCH}" in + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + sh5el) machine=sh5le-unknown ;; + *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently, or will in the future. + case "${UNAME_MACHINE_ARCH}" in + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + eval $set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep __ELF__ >/dev/null + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case "${UNAME_VERSION}" in + Debian*) + release='-gnu' + ;; + *) + release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}" + exit ;; + *:OpenBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} + exit ;; + *:ekkoBSD:*:*) + echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} + exit ;; + *:SolidBSD:*:*) + echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} + exit ;; + macppc:MirBSD:*:*) + echo powerpc-unknown-mirbsd${UNAME_RELEASE} + exit ;; + *:MirBSD:*:*) + echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} + exit ;; + alpha:OSF1:*:*) + case $UNAME_RELEASE in + *4.0) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + ;; + *5.*) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + ;; + esac + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case "$ALPHA_CPU_TYPE" in + "EV4 (21064)") + UNAME_MACHINE="alpha" ;; + "EV4.5 (21064)") + UNAME_MACHINE="alpha" ;; + "LCA4 (21066/21068)") + UNAME_MACHINE="alpha" ;; + "EV5 (21164)") + UNAME_MACHINE="alphaev5" ;; + "EV5.6 (21164A)") + UNAME_MACHINE="alphaev56" ;; + "EV5.6 (21164PC)") + UNAME_MACHINE="alphapca56" ;; + "EV5.7 (21164PC)") + UNAME_MACHINE="alphapca57" ;; + "EV6 (21264)") + UNAME_MACHINE="alphaev6" ;; + "EV6.7 (21264A)") + UNAME_MACHINE="alphaev67" ;; + "EV6.8CB (21264C)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8AL (21264B)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8CX (21264D)") + UNAME_MACHINE="alphaev68" ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE="alphaev69" ;; + "EV7 (21364)") + UNAME_MACHINE="alphaev7" ;; + "EV7.9 (21364A)") + UNAME_MACHINE="alphaev79" ;; + esac + # A Pn.n version is a patched version. + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + exit ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead + # of the specific Alpha model? + echo alpha-pc-interix + exit ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit ;; + *:[Mm]orph[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-morphos + exit ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit ;; + *:z/VM:*:*) + echo s390-ibm-zvmoe + exit ;; + *:OS400:*:*) + echo powerpc-ibm-os400 + exit ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit ;; + arm:riscos:*:*|arm:RISCOS:*:*) + echo arm-unknown-riscos + exit ;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit ;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit ;; + DRS?6000:unix:4.0:6*) + echo sparc-icl-nx6 + exit ;; + DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) echo sparc-icl-nx7; exit ;; + esac ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + i86pc:SunOS:5.*:*) + echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit ;; + m68k:machten:*:*) + echo m68k-apple-machten${UNAME_RELEASE} + exit ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && + dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`$dummy $dummyarg` && + { echo "$SYSTEM_NAME"; exit; } + echo mips-mips-riscos${UNAME_RELEASE} + exit ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit ;; + Motorola:*:4.3:PL8-*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${TARGET_BINARY_INTERFACE}x = x ] + then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else + echo i586-dg-dgux${UNAME_RELEASE} + fi + exit ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + exit ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` + then + echo "$SYSTEM_NAME" + else + echo rs6000-ibm-aix3.2.5 + fi + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit ;; + *:AIX:*:[45]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 + 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH="hppa2.0n" ;; + 64) HP_ARCH="hppa2.0w" ;; + '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 + esac ;; + esac + fi + if [ "${HP_ARCH}" = "" ]; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include + #include + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if [ ${HP_ARCH} = "hppa2.0w" ] + then + eval $set_cc_for_build + + # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating + # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler + # generating 64-bit code. GNU and HP use different nomenclature: + # + # $ CC_FOR_BUILD=cc ./config.guess + # => hppa2.0w-hp-hpux11.23 + # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess + # => hppa64-hp-hpux11.23 + + if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | + grep __LP64__ >/dev/null + then + HP_ARCH="hppa2.0w" + else + HP_ARCH="hppa64" + fi + fi + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux${HPUX_REV} + exit ;; + 3050*:HI-UX:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + echo unknown-hitachi-hiuxwe2 + exit ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + *:UNICOS/mp:*:*) + echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + 5000:UNIX_System_V:4.*:*) + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` + echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:FreeBSD:*:*) + case ${UNAME_MACHINE} in + pc98) + echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + amd64) + echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + *) + echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + esac + exit ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit ;; + i*:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit ;; + i*:windows32*:*) + # uname -m includes "-pc" on this system. + echo ${UNAME_MACHINE}-mingw32 + exit ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit ;; + x86:Interix*:[3456]*) + echo i586-pc-interix${UNAME_RELEASE} + exit ;; + EM64T:Interix*:[3456]* | authenticamd:Interix*:[3456]*) + echo x86_64-unknown-interix${UNAME_RELEASE} + exit ;; + [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) + echo i${UNAME_MACHINE}-pc-mks + exit ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # UNAME_MACHINE based on the output of uname instead of i386? + echo i586-pc-interix + exit ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit ;; + amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) + echo x86_64-unknown-cygwin + exit ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + *:GNU:*:*) + # the GNU system + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu + exit ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit ;; + arm*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + avr32*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + cris:Linux:*:*) + echo cris-axis-linux-gnu + exit ;; + crisv32:Linux:*:*) + echo crisv32-axis-linux-gnu + exit ;; + frv:Linux:*:*) + echo frv-unknown-linux-gnu + exit ;; + ia64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m32r*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m68*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + mips:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef mips + #undef mipsel + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=mipsel + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=mips + #else + CPU= + #endif + #endif +EOF + eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' + /^CPU/{ + s: ::g + p + }'`" + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } + ;; + mips64:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef mips64 + #undef mips64el + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=mips64el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=mips64 + #else + CPU= + #endif + #endif +EOF + eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' + /^CPU/{ + s: ::g + p + }'`" + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } + ;; + or32:Linux:*:*) + echo or32-unknown-linux-gnu + exit ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-gnu + exit ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-gnu + exit ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null + if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi + echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} + exit ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-unknown-linux-gnu ;; + PA8*) echo hppa2.0-unknown-linux-gnu ;; + *) echo hppa-unknown-linux-gnu ;; + esac + exit ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-gnu + exit ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo ${UNAME_MACHINE}-ibm-linux + exit ;; + sh64*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sh*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + vax:Linux:*:*) + echo ${UNAME_MACHINE}-dec-linux-gnu + exit ;; + x86_64:Linux:*:*) + echo x86_64-unknown-linux-gnu + exit ;; + i*86:Linux:*:*) + # The BFD linker knows what the default object file format is, so + # first see if it will tell us. cd to the root directory to prevent + # problems with other programs or directories called `ld' in the path. + # Set LC_ALL=C to ensure ld outputs messages in English. + ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \ + | sed -ne '/supported targets:/!d + s/[ ][ ]*/ /g + s/.*supported targets: *// + s/ .*// + p'` + case "$ld_supported_targets" in + elf32-i386) + TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" + ;; + a.out-i386-linux) + echo "${UNAME_MACHINE}-pc-linux-gnuaout" + exit ;; + coff-i386) + echo "${UNAME_MACHINE}-pc-linux-gnucoff" + exit ;; + "") + # Either a pre-BFD a.out linker (linux-gnuoldld) or + # one that does not give us useful --help. + echo "${UNAME_MACHINE}-pc-linux-gnuoldld" + exit ;; + esac + # Determine whether the default compiler is a.out or elf + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + #ifdef __ELF__ + # ifdef __GLIBC__ + # if __GLIBC__ >= 2 + LIBC=gnu + # else + LIBC=gnulibc1 + # endif + # else + LIBC=gnulibc1 + # endif + #else + #if defined(__INTEL_COMPILER) || defined(__PGI) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) + LIBC=gnu + #else + LIBC=gnuaout + #endif + #endif + #ifdef __dietlibc__ + LIBC=dietlibc + #endif +EOF + eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' + /^LIBC/{ + s: ::g + p + }'`" + test x"${LIBC}" != x && { + echo "${UNAME_MACHINE}-pc-linux-${LIBC}" + exit + } + test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; } + ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + echo i386-sequent-sysv4 + exit ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo ${UNAME_MACHINE}-pc-os2-emx + exit ;; + i*86:XTS-300:*:STOP) + echo ${UNAME_MACHINE}-unknown-stop + exit ;; + i*86:atheos:*:*) + echo ${UNAME_MACHINE}-unknown-atheos + exit ;; + i*86:syllable:*:*) + echo ${UNAME_MACHINE}-pc-syllable + exit ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit ;; + i*86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit ;; + i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit ;; + i*86:*:5:[678]*) + # UnixWare 7.x, OpenUNIX and OpenServer 6. + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + exit ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i386. + echo i386-pc-msdosdjgpp + exit ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit ;; + mc68k:UNIX:SYSTEM5:3.51m) + echo m68k-convergent-sysv + exit ;; + M680?0:D-NIX:5.3:*) + echo m68k-diab-dnix + exit ;; + M68*:*:R3V[5678]*:*) + test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; + 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4; exit; } ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*) + echo powerpc-unknown-lynxos${UNAME_RELEASE} + exit ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit ;; + i*86:VOS:*:*) + # From Paul.Green@stratus.com. + echo ${UNAME_MACHINE}-stratus-vos + exit ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + echo hppa1.1-stratus-vos + exit ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit ;; + SX-6:SUPER-UX:*:*) + echo sx6-nec-superux${UNAME_RELEASE} + exit ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Darwin:*:*) + UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown + case $UNAME_PROCESSOR in + unknown) UNAME_PROCESSOR=powerpc ;; + esac + echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} + exit ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = "x86"; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} + exit ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit ;; + NSE-?:NONSTOP_KERNEL:*:*) + echo nse-tandem-nsk${UNAME_RELEASE} + exit ;; + NSR-?:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = "386"; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo ${UNAME_MACHINE}-unknown-plan9 + exit ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit ;; + SEI:*:*:SEIUX) + echo mips-sei-seiux${UNAME_RELEASE} + exit ;; + *:DragonFly:*:*) + echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; + *:*VMS:*:*) + UNAME_MACHINE=`(uname -p) 2>/dev/null` + case "${UNAME_MACHINE}" in + A*) echo alpha-dec-vms ; exit ;; + I*) echo ia64-dec-vms ; exit ;; + V*) echo vax-dec-vms ; exit ;; + esac ;; + *:XENIX:*:SysV) + echo i386-pc-xenix + exit ;; + i*86:skyos:*:*) + echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' + exit ;; + i*86:rdos:*:*) + echo ${UNAME_MACHINE}-pc-rdos + exit ;; +esac + +#echo '(No uname command or uname output not recognized.)' 1>&2 +#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 + +eval $set_cc_for_build +cat >$dummy.c < +# include +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (__arm) && defined (__acorn) && defined (__unix) + printf ("arm-acorn-riscix\n"); exit (0); +#endif + +#if defined (hp300) && !defined (hpux) + printf ("m68k-hp-bsd\n"); exit (0); +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + if (version < 4) + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + else + printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); + +#endif + +#if defined (vax) +# if !defined (ultrix) +# include +# if defined (BSD) +# if BSD == 43 + printf ("vax-dec-bsd4.3\n"); exit (0); +# else +# if BSD == 199006 + printf ("vax-dec-bsd4.3reno\n"); exit (0); +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# endif +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# else + printf ("vax-dec-ultrix\n"); exit (0); +# endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + +# Apollos put the system type in the environment. + +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } + +# Convex versions that predate uname can use getsysinfo(1) + +if [ -x /usr/convex/getsysinfo ] +then + case `getsysinfo -f cpu_type` in + c1*) + echo c1-convex-bsd + exit ;; + c2*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + c34*) + echo c34-convex-bsd + exit ;; + c38*) + echo c38-convex-bsd + exit ;; + c4*) + echo c4-convex-bsd + exit ;; + esac +fi + +cat >&2 < in order to provide the needed +information to handle your system. + +config.guess timestamp = $timestamp + +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = ${UNAME_MACHINE} +UNAME_RELEASE = ${UNAME_RELEASE} +UNAME_SYSTEM = ${UNAME_SYSTEM} +UNAME_VERSION = ${UNAME_VERSION} +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/modules/build/config.sub b/modules/build/config.sub new file mode 100755 index 000000000..a8bdde940 --- /dev/null +++ b/modules/build/config.sub @@ -0,0 +1,1521 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + +timestamp='2003-10-16' + +# This file is (in principle) common to ALL GNU software. +# The presence of a machine in this file suggests that SOME GNU software +# can handle that machine. It does not imply ALL GNU software can. +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Please send patches to . Submit a context +# diff and a properly formatted ChangeLog entry. +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS + $0 [OPTION] ALIAS + +Canonicalize a configuration name. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.sub ($timestamp) + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 +Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit 0 ;; + --version | -v ) + echo "$version" ; exit 0 ;; + --help | --h* | -h ) + echo "$usage"; exit 0 ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo $1 + exit 0;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + nto-qnx* | linux-gnu* | linux-dietlibc | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | \ + kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple | -axis) + os= + basic_machine=$1 + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + basic_machine=$1 + ;; + -chorusos*) + os=-chorusos + basic_machine=$1 + ;; + -chorusrdb) + os=-chorusrdb + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + 1750a | 580 \ + | a29k \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ + | am33_2.0 \ + | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \ + | c4x | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | fr30 | frv \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | i370 | i860 | i960 | ia64 \ + | ip2k | iq2000 \ + | m32r | m68000 | m68k | m88k | mcore \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64vr | mips64vrel \ + | mips64orion | mips64orionel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | msp430 \ + | ns16k | ns32k \ + | openrisc | or32 \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ + | pyramid \ + | sh | sh[1234] | sh[23]e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc86x | sparclet | sparclite | sparcv9 | sparcv9b \ + | strongarm \ + | tahoe | thumb | tic4x | tic80 | tron \ + | v850 | v850e \ + | we32k \ + | x86 | xscale | xstormy16 | xtensa \ + | z8k) + basic_machine=$basic_machine-unknown + ;; + m6811 | m68hc11 | m6812 | m68hc12) + # Motorola 68HC11/12. + basic_machine=$basic_machine-unknown + os=-none + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + ;; + + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i*86 | x86_64) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + 580-* \ + | a29k-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ + | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ + | avr-* \ + | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ + | clipper-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | elxsi-* \ + | f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | i*86-* | i860-* | i960-* | ia64-* \ + | ip2k-* | iq2000-* \ + | m32r-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | mcore-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipstx39-* | mipstx39el-* \ + | msp430-* \ + | none-* | np1-* | nv1-* | ns16k-* | ns32k-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ + | pyramid-* \ + | romp-* | rs6000-* \ + | sh-* | sh[1234]-* | sh[23]e-* | sh[34]eb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc86x-* | sparclet-* | sparclite-* \ + | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \ + | tahoe-* | thumb-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ + | tron-* \ + | v850-* | v850e-* | vax-* \ + | we32k-* \ + | x86-* | x86_64-* | xps100-* | xscale-* | xstormy16-* \ + | xtensa-* \ + | ymp-* \ + | z8k-*) + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) + basic_machine=a29k-amd + os=-udi + ;; + adobe68k) + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amd64) + basic_machine=x86_64-pc + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-unknown + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=-bsd + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | j90) + basic_machine=j90-cray + os=-unicos + ;; + crds | unos) + basic_machine=m68k-crds + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + decsystem10* | dec10*) + basic_machine=pdp10-dec + os=-tops10 + ;; + decsystem20* | dec20*) + basic_machine=pdp10-dec + os=-tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + go32) + basic_machine=i386-pc + os=-go32 + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; +# I'm not sure what "Sysv32" means. Should this be sysv3.2? + i*86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i*86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i*86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i*86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) + basic_machine=i386-unknown + os=-vsta + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + mingw32) + basic_machine=i386-pc + os=-mingw32 + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + mmix*) + basic_machine=mmix-knuth + os=-mmixware + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + morphos) + basic_machine=powerpc-unknown + os=-morphos + ;; + msdos) + basic_machine=i386-pc + os=-msdos + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=-linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=-nonstopux + ;; + np1) + basic_machine=np1-gould + ;; + nv1) + basic_machine=nv1-cray + os=-unicosmp + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + or32 | or32-*) + basic_machine=or32-unknown + os=-coff + ;; + os400) + basic_machine=powerpc-ibm + os=-os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pentium | p5 | k5 | k6 | nexgen | viac3) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon | athlon_*) + basic_machine=i686-pc + ;; + pentiumii | pentium2 | pentiumiii | pentium3) + basic_machine=i686-pc + ;; + pentium4) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium4-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=power-ibm + ;; + ppc) basic_machine=powerpc-unknown + ;; + ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64) basic_machine=powerpc64-unknown + ;; + ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64le | powerpc64little | ppc64-le | powerpc64-little) + basic_machine=powerpc64le-unknown + ;; + ppc64le-* | powerpc64little-*) + basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + pw32) + basic_machine=i586-unknown + os=-pw32 + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + s390 | s390-*) + basic_machine=s390-ibm + ;; + s390x | s390x-*) + basic_machine=s390x-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sb1) + basic_machine=mipsisa64sb1-unknown + ;; + sb1el) + basic_machine=mipsisa64sb1el-unknown + ;; + sei) + basic_machine=mips-sei + os=-seiux + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparclite-wrs | simso-wrs) + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) + basic_machine=m68k-tandem + ;; + stratus) + basic_machine=i860-stratus + os=-sysv4 + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + t3e) + basic_machine=alphaev5-cray + os=-unicos + ;; + t90) + basic_machine=t90-cray + os=-unicos + ;; + tic54x | c54x*) + basic_machine=tic54x-unknown + os=-coff + ;; + tic55x | c55x*) + basic_machine=tic55x-unknown + os=-coff + ;; + tic6x | c6x*) + basic_machine=tic6x-unknown + os=-coff + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + toad1) + basic_machine=pdp10-xkl + os=-tops20 + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) + basic_machine=w65-wdc + os=-none + ;; + w89k-*) + basic_machine=hppa1.1-winbond + os=-proelf + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + ymp) + basic_machine=ymp-cray + os=-unicos + ;; + z8k-*-coff) + basic_machine=z8k-unknown + os=-sim + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) + basic_machine=hppa1.1-winbond + ;; + op50n) + basic_machine=hppa1.1-oki + ;; + op60c) + basic_machine=hppa1.1-oki + ;; + romp) + basic_machine=romp-ibm + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp10) + # there are many clones, so DEC is not a safe bet + basic_machine=pdp10-unknown + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh3 | sh4 | sh[34]eb | sh[1234]le | sh[23]ele) + basic_machine=sh-unknown + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparc | sparcv9 | sparcv9b) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) + basic_machine=powerpc-apple + ;; + *-unknown) + # Make sure to match an already-canonicalized machine name. + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -knetbsd* | -netbsd* | -openbsd* | -kfreebsd* | -freebsd* | -riscix* \ + | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -chorusos* | -chorusrdb* \ + | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux-gnu* | -linux-uclibc* | -uxpv* | -beos* | -mpeix* | -udk* \ + | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ + | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ + | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ + | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ + | -powermax* | -dnix* | -nx6 | -nx7 | -sei*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i*86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto-qnx*) + ;; + -nto*) + os=`echo $os | sed -e 's|nto|nto-qnx|'` + ;; + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* | -beos* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + -linux-dietlibc) + os=-linux-dietlibc + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -opened*) + os=-openedition + ;; + -os400*) + os=-os400 + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -atheos*) + os=-atheos + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -nova*) + os=-rtmk-nova + ;; + -ns2 ) + os=-nextstep2 + ;; + -nsk*) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) + os=-ose + ;; + -es1800*) + os=-ose + ;; + -xenix) + os=-xenix + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + os=-mint + ;; + -aros*) + os=-aros + ;; + -kaos*) + os=-kaos + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + *-acorn) + os=-riscix1.2 + ;; + arm*-rebel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + c4x-* | tic4x-*) + os=-coff + ;; + # This must come before the *-dec entry. + pdp10-*) + os=-tops20 + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + # This also exists in the configure program, but was not the + # default. + # os=-sunos4 + ;; + m68*-cisco) + os=-aout + ;; + mips*-cisco) + os=-elf + ;; + mips*-*) + os=-elf + ;; + or32-*) + os=-coff + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-be) + os=-beos + ;; + *-ibm) + os=-aix + ;; + *-wec) + os=-proelf + ;; + *-winbond) + os=-proelf + ;; + *-oki) + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f30[01]-fujitsu | f700-fujitsu) + os=-uxpv + ;; + *-rom68k) + os=-coff + ;; + *-*bug) + os=-coff + ;; + *-apple) + os=-macos + ;; + *-atari*) + os=-mint + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs* | -opened*) + vendor=ibm + ;; + -os400*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -vxsim* | -vxworks* | -windiss*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + vendor=atari + ;; + -vos*) + vendor=stratus + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os +exit 0 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: \ No newline at end of file diff --git a/modules/build/dumpenv.py b/modules/build/dumpenv.py new file mode 100644 index 000000000..6cb1a61e0 --- /dev/null +++ b/modules/build/dumpenv.py @@ -0,0 +1,36 @@ +from waflib.Build import BuildContext + +class dumpenv(BuildContext): + '''dumps the environment''' + cmd = 'dumpenv' + fun = 'build' + + def execute(self): + # Recurse through all the wscripts to find all available tasks + self.restore() + if not self.all_envs: + self.load_envs() + self.recurse([self.run_dir]) + + targets = self.targets.split(',') + defines = [] + for target in targets: + # Find the target + tsk = self.get_tgen_by_name(target) + + # Actually create the task object + tsk.post() + + # Now we can grab his defines + defines += tsk.env.DEFINES + + # Sort and uniquify it, then print them all out preceded by the + # compiler define flag + defines = sorted(list(set(defines))) + + str = '' + for define in defines: + if str: + str += ' ' + str += self.env['DEFINES_ST'] % define + print str diff --git a/modules/build/javatool.py b/modules/build/javatool.py new file mode 100644 index 000000000..fa4d20d9f --- /dev/null +++ b/modules/build/javatool.py @@ -0,0 +1,201 @@ +import os +from os.path import join, isdir, abspath, dirname +from waflib import Options, Utils, Logs, TaskGen, Errors +from waflib.Errors import ConfigurationError +from waflib.TaskGen import task_gen, feature, after, before +from waflib.Utils import to_list as listify + +def options(opt): + opt.load('java') + opt.add_option('--disable-java', action='store_false', dest='java', + help='Disable java', default=True) + opt.add_option('--with-java-home', action='store', dest='java_home', + help='Specify the location of the java home') + opt.add_option('--require-java', action='store_true', dest='force_java', + help='Require Java (configure option)', default=False) + opt.add_option('--require-jni', action='store_true', dest='force_jni', + help='Require Java lib/headers (configure option)', default=False) + opt.add_option('--require-ant', action='store_true', dest='force_ant', + help='Require Ant (configure option)', default=False) + opt.add_option('--with-ant-home', action='store', dest='ant_home', + help='Specify the Apache Ant Home - where Ant is installed') + +def configure(self): + if not Options.options.java: + return + + from build import recursiveGlob + + ant_home = Options.options.ant_home or self.environ.get('ANT_HOME', None) + if ant_home is not None: + ant_paths = [join(self.environ['ANT_HOME'], 'bin'), self.environ['ANT_HOME']] + else: + ant_paths = [] + + env = self.env + env['HAVE_ANT'] = self.find_program('ant', var='ANT', path_list=ant_paths, mandatory=False) + + if not env['ANT'] and Options.options.force_ant: + raise Errors.WafError('Cannot find ant!') + + if Options.options.java_home: + self.environ['JAVA_HOME'] = Options.options.java_home + + try: + self.load('java') + except Exception as e: + if Options.options.force_java: + raise e + else: + return + + if not self.env.CC_NAME and not self.env.CXX_NAME: + self.fatal('load a compiler first (gcc, g++, ..)') + + try: + if not self.env.JAVA_HOME: + self.fatal('set JAVA_HOME in the system environment') + + # jni requires the jvm + javaHome = abspath(self.env['JAVA_HOME'][0]) + + if not isdir(javaHome): + self.fatal('could not find JAVA_HOME directory %r (see config.log)' % javaHome) + + incDir = abspath(join(javaHome, 'include')) + if not isdir(incDir): + self.fatal('could not find include directory in %r (see config.log)' % javaHome) + + incDirs = list(set(map(lambda x: dirname(x), + recursiveGlob(incDir, ['jni.h', 'jni_md.h'])))) + libDirs = list(set(map(lambda x: dirname(x), + recursiveGlob(javaHome, ['*jvm.a', '*jvm.lib'])))) + if not libDirs: + libDirs = list(set(map(lambda x: dirname(x), + recursiveGlob(javaHome, ['*jvm.so', '*jvm.dll'])))) + + #if not self.check_jni_headers(): + if not self.check(header_name='jni.h', define_name='HAVE_JNI_H', lib='jvm', + libpath=libDirs, includes=incDirs, uselib_store='JAVA', uselib='JAVA', + function_name='JNI_GetCreatedJavaVMs'): + if Options.options.force_jni: + self.fatal('could not find lib jvm in %r (see config.log)' % libDirs) + except ConfigurationError as ex: + err = str(ex).strip() + if err.startswith('error: '): + err = err[7:] + if Options.options.force_java: + self.fatal(err) + else: + self.msg('Java lib/headers', err, color='YELLOW') + +# Used to call ant. Assumes the ant script respects a target property. +@task_gen +@feature('ant') +def ant(self): + if not hasattr(self, 'defines'): + self.defines = [] + if isinstance(self.defines, str): + self.defines = [self.defines] + self.env.ant_defines = map(lambda x: '-D%s' % x, self.defines) + self.rule = ant_exec + +def ant_exec(tsk): + # Source file is build.xml + cmd = [tsk.env['ANT'], '-file', tsk.inputs[0].abspath(), '-Dtarget=' + tsk.outputs[0].abspath()] + tsk.env.ant_defines + return tsk.generator.bld.exec_command(cmd) + +def java_module(bld, **modArgs): + """ + Builds a module, along with optional tests. + It makes assumptions, but most can be overridden by passing in args. + """ + if 'env' in modArgs: + env = modArgs['env'] + else: + variant = modArgs.get('variant', bld.env['VARIANT'] or 'default') + env = bld.all_envs[variant] + + # Basically, if this Java target depends on a JNI target, and for whatever + # reason we don't have JNI, we don't want to even add the Java target onto + # the build queue since we won't be able to build it + native_sourcedir = modArgs.get('native_sourcedir', 'src/jni') + have_native_sourcedir = bld.path.find_dir(native_sourcedir) is not None + jni_ok = bld.is_defined('HAVE_JNI_H') or not have_native_sourcedir + + if env['JAVAC'] and env['JAR'] and jni_ok: + modArgs = dict((k.lower(), v) for k, v in modArgs.iteritems()) + + lang = modArgs.get('lang', 'java') + nlang = modArgs.get('native_lang', 'c') + libExeType = {'java':'javac'}.get(lang, 'java') + nsourceExt = {'cxx':'.cpp','c':'.c'}.get(nlang, 'c') + libName = '%s.jar' % (modArgs['name']) + + path = modArgs.get('path', + 'dir' in modArgs and bld.path.find_dir(modArgs['dir']) or bld.path) + + module_deps = map(lambda x: '%s-%s' % (x, lang), listify(modArgs.get('module_deps', ''))) + uselib_local = module_deps + listify(modArgs.get('uselib_local', '')) + listify(modArgs.get('use','')) + uselib = listify(modArgs.get('uselib', '')) + ['JAVA'] + targets_to_add = listify(modArgs.get('targets_to_add', '')) + classpath = listify(modArgs.get('classpath', '')) + compat = modArgs.get('compat', '1.5') + libVersion = modArgs.get('version', None) + installPath = modArgs.get('install_path', None) + libInstallPath = modArgs.get('lib_install_path', None) + manifest = modArgs.get('manifest', None) + jarcreate = modArgs.get('jarcreate', None) + + if modArgs.get('nosuffix', False) : + targetName = modArgs['name'] + else : + targetName = '%s-%s' % (modArgs['name'], lang) + + sourcedir = modArgs.get('sourcedir', 'src/java') + + cp_targets = [] + real_classpath = [] + classpathDirs = [bld.path.find_dir('lib'), bld.path.find_dir('libs'), bld.path.find_dir('../libs')] + for cp in classpath: + for dir in classpathDirs: + if dir is not None and os.path.exists(join(dir.abspath(), cp)): + real_classpath.append(join(dir.abspath(), cp)) + cp_targets.append(bld(name=cp, features='install_tgt', install_path=libInstallPath or '${PREFIX}/lib', dir=dir, files=[cp])) + + # We need a try/catch here for the rare case where we have javac but + # not JNI, we're a module that doesn't depend on JNI, but we depend on + # another module that DOES depend on JNI. In that case, the module we + # depend on won't exist so get_tgen_by_name() will throw. There's no + # way to build this module, which is fine - we're just trying not to + # stop the whole build when something else is targetted. + for dep in module_deps: + try: + tsk = bld.get_tgen_by_name(dep) + for cp in tsk.classpath: + real_classpath.append(cp) + except: + return + + #build the jar + jar = bld(features='javac jar add_targets install_tgt', manifest=manifest, jarcreate=jarcreate, srcdir=sourcedir, classpath=real_classpath, targets_to_add=targets_to_add + cp_targets, + use=module_deps, name=targetName, target=targetName, basedir='classes', outdir='classes', destfile=libName, compat=compat, dir=bld.path.get_bld(), files=[libName]) + + jar.install_path = installPath or '${PREFIX}/lib' + + + if have_native_sourcedir: + lib = bld(features='%s %sshlib' % (nlang, nlang), includes='%s/include' % native_sourcedir, + target='%s.jni-%s' % (modArgs['name'], nlang), env=env.derive(), + uselib=uselib, use=uselib_local, + source=bld.path.find_dir(native_sourcedir).ant_glob('source/*%s' % nsourceExt)) + + jar.targets_to_add.append(lib) + + lib.install_path = installPath or '${PREFIX}/lib' + + return jar + +# Tell waf to ignore any build.xml files, the 'ant' feature will take care of them. +TaskGen.extension('build.xml')(Utils.nada) + diff --git a/modules/build/matlabtool.py b/modules/build/matlabtool.py new file mode 100644 index 000000000..52c8cbda8 --- /dev/null +++ b/modules/build/matlabtool.py @@ -0,0 +1,112 @@ +from waflib import Options, Build +from waflib.Errors import ConfigurationError +import os, subprocess, re, platform +from os.path import join, dirname, abspath + +def options(opt): + opt.add_option('--disable-matlab', action='store_false', dest='matlab', + help='Disable matlab', default=True) + opt.add_option('--with-matlab-home', action='store', dest='matlab_home', + help='Specify the location of the matlab home') + opt.add_option('--require-matlab', action='store_true', dest='force_matlab', + help='Require matlab (configure option)', default=False) + +def configure(self): + if not Options.options.matlab: + return + + from build import recursiveGlob + + matlabHome = Options.options.matlab_home or self.env['MATLAB_HOME'] + matlabBin = matlabHome and join(matlabHome, 'bin') + mandatory=Options.options.force_matlab + + # If you're on a 64-bit machine building 32-bit, you're not going to have + # the right Mex files sitting around + skipMatlab = '64' in platform.machine() and not self.env['IS64BIT'] + if skipMatlab and mandatory: + self.fatal('32-bit Matlab not available on 64-bit machines') + + if not skipMatlab and self.find_program('matlab', var='matlab', path_list=filter(None, [matlabBin]), + mandatory=mandatory): + matlabBin = dirname(self.env['matlab']) + if not matlabHome: + matlabHome = join(matlabBin, os.pardir) + + #TODO put these in a utility somewhere + winRegex = r'win32' + + incDirs = map(lambda x: os.path.dirname(x), + recursiveGlob(abspath(join(matlabHome, 'extern')), ['mex.h'])) + + exts = 'so dll lib'.split() + libs = 'mx mex mat'.split() + + searches = [] + for x in exts: + for l in libs: + searches.append('*%s.%s' % (l, x)) + + libDirs = map(lambda x: os.path.dirname(x), + recursiveGlob(matlabBin, searches)) + libDirs.extend(map(lambda x: os.path.dirname(x), + recursiveGlob(abspath(join(matlabHome, 'extern', 'lib')), searches))) + + mexExtCmd = os.path.join(matlabBin, 'mexext') + if re.match(winRegex, self.env['PLATFORM']): + archdir = self.env['IS64BIT'] and 'win64' or 'win32' + mexExtCmd += '.bat' + else: + #retrieve the matlab environment + matlabEnvCmd = '%s -nojvm -nosplash -nodisplay -e' % self.env['matlab'] + out, err = subprocess.Popen(matlabEnvCmd.split(), stdout=subprocess.PIPE, + stderr=subprocess.PIPE).communicate() + for line in out.split('\n'): + keyVal = line.split('=', 1) + if len(keyVal) == 2 and keyVal[0] == 'ARCH': + archdir = keyVal[1] + break + + # Get the appropriate mex extension. Matlab provides a script to + # tell us this. + out, err = subprocess.Popen(mexExtCmd, stdout=subprocess.PIPE, + stderr=subprocess.PIPE).communicate() + self.env['MEX_EXT'] = '.' + out.rstrip() + + filtered = filter(lambda x: archdir in x, libDirs) + if filtered: + libDirs = filtered + libDirs = list(set(libDirs)) + + self.env.append_value('CFLAGS_MEX', '-DMATLAB_MEX_FILE'.split()) +# self.env.append_value('LINKFLAGS_MEX', '-Wl,-rpath-link,%s' % ':'.join(libDirs)) + try: + env = self.env.derive() + + self.check(header_name='mex.h', define_name='HAVE_MEX_H', + includes=incDirs, uselib_store='MEX', uselib='MEX', + mandatory=True, env=env) + + libPrefix = '' + if re.match(winRegex, self.env['PLATFORM']): + libPrefix = 'lib' + + # self.check(lib='%smat' % libPrefix, libpath=libDirs, uselib_store='MEX', uselib='MEX', + # type='cshlib', mandatory=True, env=env) + self.check(lib='%smex' % libPrefix, libpath=libDirs, uselib_store='MEX', uselib='MEX', + mandatory=True, env=env) + self.check(lib='%smx' % libPrefix, libpath=libDirs, uselib_store='MEX', uselib='MEX', + mandatory=True, env=env) + + if re.match(winRegex, self.env['PLATFORM']): + self.env.append_value('LINKFLAGS_MEX', '/EXPORT:mexFunction'.split()) + + except ConfigurationError as ex: + err = str(ex).strip() + if err.startswith('error: '): + err = err[7:] + if mandatory: + self.fatal(err) + else: + self.undefine('HAVE_MEX_H') + self.msg('matlab/mex lib/headers', err, color='YELLOW') diff --git a/modules/build/msvs.py b/modules/build/msvs.py new file mode 100644 index 000000000..a4faa4b00 --- /dev/null +++ b/modules/build/msvs.py @@ -0,0 +1,1021 @@ +#! /usr/bin/env python +# encoding: utf-8 +# Avalanche Studios 2009-2011 +# Thomas Nagy 2011 + +""" +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +""" + +""" +To add this tool to your project: +def options(conf): + opt.load('msvs') + +It can be a good idea to add the sync_exec tool too. + +To generate solution files: +$ waf configure msvs + +To customize the outputs, provide subclasses in your wscript files: + +from waflib.extras import msvs +class vsnode_target(msvs.vsnode_target): + def get_build_command(self, props): + # likely to be required + return "waf.bat build" + def collect_source(self): + # likely to be required + ... +class msvs_bar(msvs.msvs_generator): + def init(self): + msvs.msvs_generator.init(self) + self.vsnode_target = vsnode_target + +The msvs class re-uses the same build() function for reading the targets (task generators), +you may therefore specify msvs settings on the context object: + +def build(bld): + bld.solution_name = 'foo.sln' + bld.waf_command = 'waf.bat' + bld.projects_dir = bld.srcnode.make_node('.depproj') + bld.projects_dir.mkdir() + +For visual studio 2008, the command is called 'msvs2008', and the classes +such as vsnode_target are wrapped by a decorator class 'wrap_2008' to +provide special functionality. + +ASSUMPTIONS: +* a project can be either a directory or a target, vcxproj files are written only for targets that have source files +* each project is a vcxproj file, therefore the project uuid needs only to be a hash of the absolute path +""" + +import os, re, sys +import uuid # requires python 2.5 +from waflib.Build import BuildContext +from waflib import Utils, TaskGen, Logs, Task, Context, Node, Options + +HEADERS_GLOB = '**/(*.h|*.hpp|*.H|*.inl)' + +PROJECT_TEMPLATE = r''' + + + + ${for b in project.build_properties} + + ${b.configuration} + ${b.platform} + + ${endfor} + + + + {${project.uuid}} + MakeFileProj + ${project.name} + + + + ${for b in project.build_properties} + + Makefile + ${b.outdir} + + ${endfor} + + + + + + ${for b in project.build_properties} + + + + ${endfor} + + ${for b in project.build_properties} + + ${xml:project.get_build_command(b)} + ${xml:project.get_rebuild_command(b)} + ${xml:project.get_clean_command(b)} + ${xml:b.includes_search_path} + ${xml:b.preprocessor_definitions};$(NMakePreprocessorDefinitions) + ${xml:b.includes_search_path} + $(ExecutablePath) + + ${if getattr(b, 'output_file', None)} + ${xml:b.output_file} + ${endif} + ${if getattr(b, 'deploy_dir', None)} + ${xml:b.deploy_dir} + ${endif} + + ${endfor} + + ${for b in project.build_properties} + ${if getattr(b, 'deploy_dir', None)} + + + CopyToHardDrive + + + ${endif} + ${endfor} + + + ${for x in project.source} + <${project.get_key(x)} Include='${x.abspath()}' /> + ${endfor} + + + + + +''' + +FILTER_TEMPLATE = ''' + + + ${for x in project.source} + <${project.get_key(x)} Include="${x.abspath()}"> + ${project.get_filter_name(x.parent)} + + ${endfor} + + + ${for x in project.dirs()} + + {${project.make_uuid(x.abspath())}} + + ${endfor} + + +''' + +PROJECT_2008_TEMPLATE = r''' + + + ${if project.build_properties} + ${for b in project.build_properties} + + ${endfor} + ${else} + + ${endif} + + + + + ${if project.build_properties} + ${for b in project.build_properties} + + + + ${endfor} + ${else} + + + ${endif} + + + + +${project.display_filter()} + + +''' + +SOLUTION_TEMPLATE = '''Microsoft Visual Studio Solution File, Format Version ${project.numver} +# Visual Studio ${project.vsver} +${for p in project.all_projects} +Project("{${p.ptype()}}") = "${p.name}", "${p.title}", "{${p.uuid}}" +EndProject${endfor} +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + ${if project.all_projects} + ${for (configuration, platform) in project.all_projects[0].ctx.project_configurations()} + ${configuration}|${platform} = ${configuration}|${platform} + ${endfor} + ${endif} + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + ${for p in project.all_projects} + ${if hasattr(p, 'source')} + ${for b in p.build_properties} + {${p.uuid}}.${b.configuration}|${b.platform}.ActiveCfg = ${b.configuration}|${b.platform} + ${if getattr(p, 'is_active', None)} + {${p.uuid}}.${b.configuration}|${b.platform}.Build.0 = ${b.configuration}|${b.platform} + ${endif} + ${endfor} + ${endif} + ${endfor} + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + ${for p in project.all_projects} + ${if p.parent} + {${p.uuid}} = {${p.parent.uuid}} + ${endif} + ${endfor} + EndGlobalSection +EndGlobal +''' + +COMPILE_TEMPLATE = '''def f(project): + lst = [] + def xml_escape(value): + return value.replace("&", "&").replace('"', """).replace("'", "'").replace("<", "<").replace(">", ">") + + %s + + #f = open('cmd.txt', 'w') + #f.write(str(lst)) + #f.close() + return ''.join(lst) +''' +reg_act = re.compile(r"(?P\\)|(?P\$\$)|(?P\$\{(?P[^}]*?)\})", re.M) +def compile_template(line): + """ + Compile a template expression into a python function (like jsps, but way shorter) + """ + extr = [] + def repl(match): + g = match.group + if g('dollar'): return "$" + elif g('backslash'): + return "\\" + elif g('subst'): + extr.append(g('code')) + return "<<|@|>>" + return None + + line2 = reg_act.sub(repl, line) + params = line2.split('<<|@|>>') + assert(extr) + + + indent = 0 + buf = [] + app = buf.append + + def app(txt): + buf.append(indent * '\t' + txt) + + for x in range(len(extr)): + if params[x]: + app("lst.append(%r)" % params[x]) + + f = extr[x] + if f.startswith('if') or f.startswith('for'): + app(f + ':') + indent += 1 + elif f.startswith('py:'): + app(f[3:]) + elif f.startswith('endif') or f.startswith('endfor'): + indent -= 1 + elif f.startswith('else') or f.startswith('elif'): + indent -= 1 + app(f + ':') + indent += 1 + elif f.startswith('xml:'): + app('lst.append(xml_escape(%s))' % f[4:]) + else: + #app('lst.append((%s) or "cannot find %s")' % (f, f)) + app('lst.append(%s)' % f) + + if extr: + if params[-1]: + app("lst.append(%r)" % params[-1]) + + fun = COMPILE_TEMPLATE % "\n\t".join(buf) + #print(fun) + return Task.funex(fun) + + +re_blank = re.compile('(\n|\r|\\s)*\n', re.M) +def rm_blank_lines(txt): + txt = re_blank.sub('\r\n', txt) + return txt + +BOM = '\xef\xbb\xbf' +try: + BOM = bytes(BOM, 'iso8859-1') # python 3 +except: + pass + +def stealth_write(self, data, flags='wb'): + try: + x = unicode + except: + data = data.encode('utf-8') # python 3 + else: + data = data.decode(sys.getfilesystemencoding(), 'replace') + data = data.encode('utf-8') + + if self.name.endswith('.vcproj') or self.name.endswith('.vcxproj'): + data = BOM + data + + try: + txt = self.read(flags='rb') + if txt != data: + raise ValueError('must write') + except (IOError, ValueError): + self.write(data, flags=flags) + else: + Logs.debug('msvs: skipping %s' % self.abspath()) +Node.Node.stealth_write = stealth_write + +re_quote = re.compile("[^a-zA-Z0-9-]") +def quote(s): + return re_quote.sub("_", s) + +def xml_escape(value): + return value.replace("&", "&").replace('"', """).replace("'", "'").replace("<", "<").replace(">", ">") + +def make_uuid(v, prefix = None): + """ + simple utility function + """ + if isinstance(v, dict): + keys = list(v.keys()) + keys.sort() + tmp = str([(k, v[k]) for k in keys]) + else: + tmp = str(v) + d = Utils.md5(tmp.encode()).hexdigest().upper() + if prefix: + d = '%s%s' % (prefix, d[8:]) + gid = uuid.UUID(d, version = 4) + return str(gid).upper() + +def diff(node, fromnode): + # difference between two nodes, but with "(..)" instead of ".." + c1 = node + c2 = fromnode + + c1h = c1.height() + c2h = c2.height() + + lst = [] + up = 0 + + while c1h > c2h: + lst.append(c1.name) + c1 = c1.parent + c1h -= 1 + + while c2h > c1h: + up += 1 + c2 = c2.parent + c2h -= 1 + + while id(c1) != id(c2): + lst.append(c1.name) + up += 1 + + c1 = c1.parent + c2 = c2.parent + + for i in range(up): + lst.append('(..)') + lst.reverse() + return tuple(lst) + +class build_property(object): + pass + +class vsnode(object): + """ + Abstract class representing visual studio elements + We assume that all visual studio nodes have a uuid and a parent + """ + def __init__(self, ctx): + self.ctx = ctx # msvs context + self.name = '' # string, mandatory + self.vspath = '' # path in visual studio (name for dirs, absolute path for projects) + self.uuid = '' # string, mandatory + self.parent = None # parent node for visual studio nesting + + def get_waf(self): + """ + Override in subclasses... + """ + return 'cd /d "%s" & %s' % (self.ctx.srcnode.abspath(), getattr(self.ctx, 'waf_command', 'waf.bat')) + + def ptype(self): + """ + Return a special uuid for projects written in the solution file + """ + pass + + def write(self): + """ + Write the project file, by default, do nothing + """ + pass + + def make_uuid(self, val): + """ + Alias for creating uuid values easily (the templates cannot access global variables) + """ + return make_uuid(val) + +class vsnode_vsdir(vsnode): + """ + Nodes representing visual studio folders (which do not match the filesystem tree!) + """ + VS_GUID_SOLUTIONFOLDER = "2150E333-8FDC-42A3-9474-1A3956D46DE8" + def __init__(self, ctx, uuid, name, vspath=''): + vsnode.__init__(self, ctx) + self.title = self.name = name + self.uuid = uuid + self.vspath = vspath or name + + def ptype(self): + return self.VS_GUID_SOLUTIONFOLDER + +class vsnode_project(vsnode): + """ + Abstract class representing visual studio project elements + A project is assumed to be writable, and has a node representing the file to write to + """ + VS_GUID_VCPROJ = "8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942" + def ptype(self): + return self.VS_GUID_VCPROJ + + def __init__(self, ctx, node): + vsnode.__init__(self, ctx) + self.path = node + self.uuid = make_uuid(node.abspath()) + self.name = node.name + self.title = self.path.abspath() + self.source = [] # list of node objects + self.build_properties = [] # list of properties (nmake commands, output dir, etc) + + def dirs(self): + """ + Get the list of parent folders of the source files (header files included) + for writing the filters + """ + lst = [] + def add(x): + if x.height() > self.tg.path.height() and x not in lst: + lst.append(x) + add(x.parent) + for x in self.source: + add(x.parent) + return lst + + def write(self): + Logs.debug('msvs: creating %r' % self.path) + + # first write the project file + template1 = compile_template(PROJECT_TEMPLATE) + proj_str = template1(self) + proj_str = rm_blank_lines(proj_str) + self.path.stealth_write(proj_str) + + # then write the filter + template2 = compile_template(FILTER_TEMPLATE) + filter_str = template2(self) + filter_str = rm_blank_lines(filter_str) + tmp = self.path.parent.make_node(self.path.name + '.filters') + tmp.stealth_write(filter_str) + + def get_key(self, node): + """ + required for writing the source files + """ + name = node.name + if name.endswith('.cpp') or name.endswith('.c'): + return 'ClCompile' + return 'ClInclude' + + def collect_properties(self): + """ + Returns a list of triplet (configuration, platform, output_directory) + """ + ret = [] + for c in self.ctx.configurations: + for p in self.ctx.platforms: + x = build_property() + x.outdir = '' + + x.configuration = c + x.platform = p + + x.preprocessor_definitions = '' + x.includes_search_path = '' + + # can specify "deploy_dir" too + ret.append(x) + self.build_properties = ret + + def get_build_params(self, props): + opt = '--execsolution=%s' % self.ctx.get_solution_node().abspath() + return (self.get_waf(), opt) + + def get_build_command(self, props): + return "%s build %s" % self.get_build_params(props) + + def get_clean_command(self, props): + return "%s clean %s" % self.get_build_params(props) + + def get_rebuild_command(self, props): + return "%s clean build %s" % self.get_build_params(props) + + def get_filter_name(self, node): + lst = diff(node, self.tg.path) + return '\\'.join(lst) or '.' + +class vsnode_alias(vsnode_project): + def __init__(self, ctx, node, name): + vsnode_project.__init__(self, ctx, node) + self.name = name + self.output_file = '' + +class vsnode_build_all(vsnode_alias): + """ + Fake target used to emulate the behaviour of "make all" (starting one process by target is slow) + This is the only alias enabled by default + """ + def __init__(self, ctx, node, name='build_all_projects'): + vsnode_alias.__init__(self, ctx, node, name) + self.is_active = True + +class vsnode_install_all(vsnode_alias): + """ + Fake target used to emulate the behaviour of "make install" + """ + def __init__(self, ctx, node, name='install_all_projects'): + vsnode_alias.__init__(self, ctx, node, name) + + def get_build_command(self, props): + return "%s build install %s" % self.get_build_params(props) + + def get_clean_command(self, props): + return "%s clean %s" % self.get_build_params(props) + + def get_rebuild_command(self, props): + return "%s clean build install %s" % self.get_build_params(props) + +class vsnode_project_view(vsnode_alias): + """ + Fake target used to emulate a file system view + """ + def __init__(self, ctx, node, name='project_view'): + vsnode_alias.__init__(self, ctx, node, name) + self.tg = self.ctx() # fake one, cannot remove + self.exclude_files = Node.exclude_regs + ''' +waf-1.6.* +waf3-1.6.*/** +.waf-1.6.* +.waf3-1.6.*/** +**/*.sdf +**/*.suo +**/*.ncb +**/%s + ''' % Options.lockfile + + def collect_source(self): + # this is likely to be slow + self.source = self.ctx.srcnode.ant_glob('**', excl=self.exclude_files) + + def get_build_command(self, props): + params = self.get_build_params(props) + (self.ctx.cmd,) + return "%s %s %s" % params + + def get_clean_command(self, props): + return "" + + def get_rebuild_command(self, props): + return self.get_build_command(props) + +class vsnode_target(vsnode_project): + """ + Visual studio project representing a targets (programs, libraries, etc) and bound + to a task generator + """ + def __init__(self, ctx, tg): + """ + A project is more or less equivalent to a file/folder + """ + base = getattr(ctx, 'projects_dir', None) or tg.path + node = base.make_node(quote(tg.name) + ctx.project_extension) # the project file as a Node + vsnode_project.__init__(self, ctx, node) + self.name = quote(tg.name) + self.tg = tg # task generator + + def get_build_params(self, props): + """ + Override the default to add the target name + """ + opt = '--execsolution=%s' % self.ctx.get_solution_node().abspath() + if getattr(self, 'tg', None): + opt += " --targets=%s" % self.tg.name + return (self.get_waf(), opt) + + def collect_source(self): + tg = self.tg + source_files = tg.to_nodes(getattr(tg, 'source', [])) + include_dirs = Utils.to_list(getattr(tg, 'msvs_includes', [])) + include_files = [] + for x in include_dirs: + if isinstance(x, str): + x = tg.path.find_node(x) + if x: + lst = [y for y in x.ant_glob(HEADERS_GLOB, flat=False)] + include_files.extend(lst) + + # remove duplicates + self.source.extend(list(set(source_files + include_files))) + self.source.sort(key=lambda x: x.abspath()) + + def collect_properties(self): + """ + Visual studio projects are associated with platforms and configurations (for building especially) + """ + super(vsnode_target, self).collect_properties() + for x in self.build_properties: + x.outdir = self.path.parent.abspath() + x.preprocessor_definitions = '' + x.includes_search_path = '' + + try: + tsk = self.tg.link_task + except AttributeError: + pass + else: + x.output_file = tsk.outputs[0].abspath() + x.preprocessor_definitions = ';'.join(tsk.env.DEFINES) + x.includes_search_path = ';'.join(self.tg.env.INCPATHS) + +class msvs_generator(BuildContext): + '''generates a visual studio 2010 solution''' + cmd = 'msvs' + fun = 'build' + + def init(self): + """ + Some data that needs to be present + """ + if not getattr(self, 'configurations', None): + self.configurations = ['Release'] # LocalRelease, RemoteDebug, etc + if not getattr(self, 'platforms', None): + self.platforms = ['Win32'] + if not getattr(self, 'all_projects', None): + self.all_projects = [] + if not getattr(self, 'project_extension', None): + self.project_extension = '.vcxproj' + if not getattr(self, 'projects_dir', None): + self.projects_dir = self.srcnode.make_node('.depproj') + self.projects_dir.mkdir() + + # bind the classes to the object, so that subclass can provide custom generators + if not getattr(self, 'vsnode_vsdir', None): + self.vsnode_vsdir = vsnode_vsdir + if not getattr(self, 'vsnode_target', None): + self.vsnode_target = vsnode_target + if not getattr(self, 'vsnode_build_all', None): + self.vsnode_build_all = vsnode_build_all + if not getattr(self, 'vsnode_install_all', None): + self.vsnode_install_all = vsnode_install_all + if not getattr(self, 'vsnode_project_view', None): + self.vsnode_project_view = vsnode_project_view + + self.numver = '11.00' + self.vsver = '2010' + + def execute(self): + """ + Entry point + """ + self.restore() + if not self.all_envs: + self.load_envs() + self.recurse([self.run_dir]) + + # user initialization + self.init() + + # two phases for creating the solution + self.collect_projects() # add project objects into "self.all_projects" + self.write_files() # write the corresponding project and solution files + + def collect_projects(self): + """ + Fill the list self.all_projects with project objects + Fill the list of build targets + """ + self.collect_targets() + self.add_aliases() + self.collect_dirs() + default_project = getattr(self, 'default_project', None) + def sortfun(x): + if x.name == default_project: + return '' + return getattr(x, 'path', None) and x.path.abspath() or x.name + self.all_projects.sort(key=sortfun) + + def write_files(self): + """ + Write the project and solution files from the data collected + so far. It is unlikely that you will want to change this + """ + for p in self.all_projects: + p.write() + + # and finally write the solution file + node = self.get_solution_node() + node.parent.mkdir() + Logs.warn('Creating %r' % node) + template1 = compile_template(SOLUTION_TEMPLATE) + sln_str = template1(self) + sln_str = rm_blank_lines(sln_str) + node.stealth_write(sln_str) + + def get_solution_node(self): + """ + The solution filename is required when writing the .vcproj files + return self.solution_node and if it does not exist, make one + """ + try: + return self.solution_node + except: + pass + + solution_name = getattr(self, 'solution_name', None) + if not solution_name: + solution_name = getattr(Context.g_module, Context.APPNAME, 'project') + '.sln' + if os.path.isabs(solution_name): + self.solution_node = self.root.make_node(solution_name) + else: + self.solution_node = self.srcnode.make_node(solution_name) + return self.solution_node + + def project_configurations(self): + """ + Helper that returns all the pairs (config,platform) + """ + ret = [] + for c in self.configurations: + for p in self.platforms: + ret.append((c, p)) + return ret + + def collect_targets(self): + """ + Process the list of task generators + """ + for g in self.groups: + for tg in g: + if not isinstance(tg, TaskGen.task_gen): + continue + + if not hasattr(tg, 'msvs_includes'): + tg.msvs_includes = tg.to_list(getattr(tg, 'includes', [])) + tg.to_list(getattr(tg, 'export_includes', [])) + tg.post() + if not getattr(tg, 'link_task', None): + continue + + p = self.vsnode_target(self, tg) + p.collect_source() # delegate this processing + p.collect_properties() + self.all_projects.append(p) + + def add_aliases(self): + """ + Add a specific target that emulates the "make all" necessary for Visual studio when pressing F7 + We also add an alias for "make install" (disabled by default) + """ + base = getattr(self, 'projects_dir', None) or self.tg.path + + node_project = base.make_node('build_all_projects' + self.project_extension) # Node + p_build = self.vsnode_build_all(self, node_project) + p_build.collect_properties() + self.all_projects.append(p_build) + + node_project = base.make_node('install_all_projects' + self.project_extension) # Node + p_install = self.vsnode_install_all(self, node_project) + p_install.collect_properties() + self.all_projects.append(p_install) + + node_project = base.make_node('project_view' + self.project_extension) # Node + p_view = self.vsnode_project_view(self, node_project) + p_view.collect_source() + p_view.collect_properties() + self.all_projects.append(p_view) + + n = self.vsnode_vsdir(self, make_uuid(self.srcnode.abspath() + 'build_aliases'), "build_aliases") + p_build.parent = p_install.parent = p_view.parent = n + self.all_projects.append(n) + + def collect_dirs(self): + """ + Create the folder structure in the Visual studio project view + """ + seen = {} + def make_parents(proj): + # look at a project, try to make a parent + if getattr(proj, 'parent', None): + # aliases already have parents + return + x = proj.iter_path + if x in seen: + proj.parent = seen[x] + return + + # There is not vsnode_vsdir for x. + # So create a project representing the folder "x" + n = proj.parent = seen[x] = self.vsnode_vsdir(self, make_uuid(x.abspath()), x.name) + n.iter_path = x.parent + self.all_projects.append(n) + + # recurse up to the project directory + if x.height() > self.srcnode.height() + 1: + make_parents(n) + + for p in self.all_projects[:]: # iterate over a copy of all projects + if not getattr(p, 'tg', None): + # but only projects that have a task generator + continue + + # make a folder for each task generator + p.iter_path = p.tg.path + make_parents(p) + +def wrap_2008(cls): + class dec(cls): + def __init__(self, *k, **kw): + cls.__init__(self, *k, **kw) + self.project_template = PROJECT_2008_TEMPLATE + + def display_filter(self): + + root = build_property() + root.subfilters = [] + root.sourcefiles = [] + root.source = [] + root.name = '' + + @Utils.run_once + def add_path(lst): + if not lst: + return root + child = build_property() + child.subfilters = [] + child.sourcefiles = [] + child.source = [] + child.name = lst[-1] + + par = add_path(lst[:-1]) + par.subfilters.append(child) + return child + + for x in self.source: + # this crap is for enabling subclasses to override get_filter_name + tmp = self.get_filter_name(x.parent) + tmp = tmp != '.' and tuple(tmp.split('\\')) or () + par = add_path(tmp) + par.source.append(x) + + def display(n): + buf = [] + for x in n.source: + buf.append('\n' % (xml_escape(x.abspath()), self.get_key(x))) + for x in n.subfilters: + buf.append('' % xml_escape(x.name)) + buf.append(display(x)) + buf.append('') + return '\n'.join(buf) + + return display(root) + + def get_key(self, node): + """ + If you do not want to let visual studio use the default file extensions, + override this method to return a value: + 0: C/C++ Code, 1: C++ Class, 2: C++ Header File, 3: C++ Form, + 4: C++ Control, 5: Text File, 6: DEF File, 7: IDL File, + 8: Makefile, 9: RGS File, 10: RC File, 11: RES File, 12: XSD File, + 13: XML File, 14: HTML File, 15: CSS File, 16: Bitmap, 17: Icon, + 18: Resx File, 19: BSC File, 20: XSX File, 21: C++ Web Service, + 22: ASAX File, 23: Asp Page, 24: Document, 25: Discovery File, + 26: C# File, 27: eFileTypeClassDiagram, 28: MHTML Document, + 29: Property Sheet, 30: Cursor, 31: Manifest, 32: eFileTypeRDLC + """ + return '' + + def write(self): + Logs.debug('msvs: creating %r' % self.path) + template1 = compile_template(self.project_template) + proj_str = template1(self) + proj_str = rm_blank_lines(proj_str) + self.path.stealth_write(proj_str) + + return dec + +class msvs_2008_generator(msvs_generator): + '''generates a visual studio 2008 solution''' + cmd = 'msvs2008' + fun = msvs_generator.fun + + def init(self): + if not getattr(self, 'project_extension', None): + self.project_extension = '_2008.vcproj' + if not getattr(self, 'solution_name', None): + self.solution_name = getattr(Context.g_module, Context.APPNAME, 'project') + '_2008.sln' + + if not getattr(self, 'vsnode_target', None): + self.vsnode_target = wrap_2008(vsnode_target) + if not getattr(self, 'vsnode_build_all', None): + self.vsnode_build_all = wrap_2008(vsnode_build_all) + if not getattr(self, 'vsnode_install_all', None): + self.vsnode_install_all = wrap_2008(vsnode_install_all) + if not getattr(self, 'vsnode_project_view', None): + self.vsnode_project_view = wrap_2008(vsnode_project_view) + + msvs_generator.init(self) + self.numver = '10.00' + self.vsver = '2008' + +def options(ctx): + """ + If the msvs option is used, try to detect if the build is made from visual studio + """ + ctx.add_option('--execsolution', action='store', help='when building with visual studio, use a build state file') + + old = BuildContext.execute + def override_build_state(ctx): + def lock(rm, add): + uns = ctx.options.execsolution.replace('.sln', rm) + uns = ctx.root.make_node(uns) + try: + uns.delete() + except: + pass + + uns = ctx.options.execsolution.replace('.sln', add) + uns = ctx.root.make_node(uns) + try: + uns.write('') + except: + pass + + if ctx.options.execsolution: + ctx.launch_dir = Context.top_dir # force a build for the whole project (invalid cwd when called by visual studio) + lock('.lastbuildstate', '.unsuccessfulbuild') + old(ctx) + lock('.unsuccessfulbuild', '.lastbuildstate') + else: + old(ctx) + BuildContext.execute = override_build_state + diff --git a/modules/build/pythontool.py b/modules/build/pythontool.py new file mode 100644 index 000000000..baf1d30da --- /dev/null +++ b/modules/build/pythontool.py @@ -0,0 +1,58 @@ +from waflib import Options +import os, re + +def options(opt): + opt.load('python') + opt.add_option('--disable-python', action='store_false', dest='python', + help='Disable python', default=True) + opt.add_option('--python-version', action='store', dest='python_version', + default=None, help='Specify the minimum python version') + opt.add_option('--require-python', action='store_true', dest='force_python', + help='Require Python program (configure option)', default=False) + opt.add_option('--python-dev', action='store_true', dest='python_dev', + help='Require Python lib/headers (configure option)', default=False) + +def configure(conf): + if Options.options.python: + + try: + conf.load('python') + if not conf.env['PYTHON']: + raise Exception('python not found') + except Exception as e: + if Options.options.force_python: + raise e + else: + return + + pyver = Options.options.python_version + if pyver: + pyver = map(int, pyver.split('.')) + conf.check_python_version(minver=pyver) + + # The waf python tool uses distutils.msvccompiler, tell it that we've already setup msvc. + winRegex = r'win32' + if re.match(winRegex, conf.env['PLATFORM']): + os.environ['DISTUTILS_USE_SDK'] = '1' + os.environ['MSSdk'] = '1' + + try: + conf.check_python_headers() + conf.msg('Can build python bindings', 'yes', color='GREEN') + except Exception as ex: + print ex + err = str(ex).strip() + if err.startswith('error: '): + err = err[7:] + err = err + ' (Is python built with -fPIC?)' + if Options.options.python_dev: + conf.fatal(err) + else: + conf.msg('Python lib/headers', err, color='YELLOW') + + # The python config tool in waf 1.6.11 tries to override our msvc config.. + if re.match(winRegex, conf.env['PLATFORM']): + conf.env['CFLAGS_PYEXT'] = [] + conf.env['CXXFLAGS_PYEXT'] = [] + conf.env['LINKFLAGS_PYEXT'] = [] + diff --git a/modules/build/scripts/jenkins.py b/modules/build/scripts/jenkins.py new file mode 100755 index 000000000..c67d2ba06 --- /dev/null +++ b/modules/build/scripts/jenkins.py @@ -0,0 +1,91 @@ +import zipfile, glob, sys +import os, platform, shutil +from subprocess import check_call +from optparse import OptionParser +import platform + +parser = OptionParser() +parser.add_option("-p", "--package", dest="package_name", help="Package name") +parser.add_option("-d", "--build-dir", dest="build_dir", help="Build Directory", default=".") +parser.add_option("-c", "--config-options", dest="config_options", help="Configure Options") +parser.add_option("-b", "--build-options", dest="build_options", help="Build Options") +parser.add_option("--studio11-path", dest="studio11_path", help="Sun Studio 11 Compiler Path", default="/var/studio11/SUNWspro") +parser.add_option("--studio12-path", dest="studio12_path", help="Sun Studio 12 Compiler Path", default="/opt/solarisstudio12.3") +parser.add_option("--python27-path", dest="python27_path", help="Python 2.7.x Path", default="/opt/python/v2.7.3") +parser.add_option("--no-distclean", dest="do_distclean", help="No distclean at the end of the build", action="store_false", default=True) + +(options, args) = parser.parse_args() + +if not options.package_name or not options.build_dir: + print 'You must specify package name and build directory' + sys.exit(1) + +install_suffix = '' + +package_name = options.package_name +build_dir = options.build_dir +if options.config_options is not None: + config_options = options.config_options.split(',') +else: + config_options = [] +if options.build_options is not None: + build_options = options.build_options.split(',') +else: + build_options = [] + +print 'Package Name: %s' % package_name +print 'Build Dir: %s' % build_dir +print 'Config Options: %s' % config_options +print 'Build Options: %s' % build_options + +if 'studio11' in os.environ.get('JOB_NAME'): + print 'Studio 11 Path: %s' % options.studio11_path + os.environ['PATH'] += os.pathsep + ('%s/bin' % options.studio11_path) + os.environ['LD_LIBRARY_PATH'] += os.pathsep + ('%s/lib' % options.studio11_path) + install_suffix = 'sparc-sun-solaris2.10-64-studio11' + print 'Path: %s' % os.environ['PATH'] +elif 'studio12' in os.environ.get('JOB_NAME') or 'solaris' in os.environ.get('JOB_NAME'): + print 'Studio 12 Path: %s' % options.studio12_path + os.environ['PATH'] += os.pathsep + ('%s/bin' % options.studio12_path) + os.environ['LD_LIBRARY_PATH'] += os.pathsep + ('%s/lib' % options.studio12_path) + install_suffix = 'sparc-sun-solaris2.10-64-studio12' +elif 'linux' in os.environ.get('JOB_NAME'): + os.environ['PATH'] += os.pathsep + ('%s/bin' % options.python27_path) + install_suffix = 'x86_64-linux-gnu-64' +elif 'win32' in os.environ.get('JOB_NAME'): + install_suffix = 'win32' + if platform.architecture()[0] == '64bit': + # We're a 64-bit machine but running a 32-bit job + java_home32 = os.environ.get('JAVA_HOME_32') + if java_home32: + os.environ['JAVA_HOME'] = java_home32 + config_options += ['--enable-32bit'] +elif 'win64' in os.environ.get('JOB_NAME'): + install_suffix = 'win64' +if '-mt' in os.environ.get('JOB_NAME'): + install_suffix += '-mt' + config_options += ["--with-crt=MT"] +if '-vc9' in os.environ.get('JOB_NAME'): + install_suffix += '-vc9' + config_options += ["--msvc_version=\"msvc 9.0\""] + +print 'Job: %s' % os.environ.get('JOB_NAME', '') +print "Revision: %s" % os.environ.get('SVN_REVISION', '') +print "LD_LIBRARY_PATH: %s" % os.environ.get('LD_LIBRARY_PATH','') +install_path = "%s-%s-r%s" % (package_name,install_suffix,os.environ.get('SVN_REVISION', '')) + +os.chdir(build_dir) +for f in glob.glob('%s-*' % package_name): + if os.path.isdir(f): + shutil.rmtree(f, True) + else: + os.remove(f) + +check_call(["python", "waf", "distclean"]) +check_call(["python", "waf", "configure", "--prefix=%s" % install_path] + config_options) +check_call(["python", "waf", "install"] + build_options) +if options.do_distclean: + check_call(["python", "waf", "distclean"]) + +if os.path.isdir(install_path): + shutil.make_archive(install_path, "zip", install_path) diff --git a/modules/build/scripts/makeEnums.py b/modules/build/scripts/makeEnums.py new file mode 100755 index 000000000..e718c6008 --- /dev/null +++ b/modules/build/scripts/makeEnums.py @@ -0,0 +1,207 @@ +#!/usr/bin/env python + +import sys, os, re +try: + from configparser import ConfigParser +except: + from ConfigParser import ConfigParser + +from os.path import dirname, join + +from StringIO import StringIO + + +def Bunch(**kw): + return type('Bunch',(), kw) + +def makeEnums(filenames): + c = ConfigParser() + c.optionxform = str + c.read(filenames) + + s = StringIO() + sections = list(c.sections()) + sections = sorted(sections) + for enum in sections: + values = Bunch(default=0, prefix='', items=[], + supportNoPrefixForStrings=False, + toStringNoPrefix=False, + constShortcuts=False, + cleanPrefix='') + for (name, value) in c.items(enum): + name, value = map(lambda x: x.strip(), [name, value]) + if name == '__default__': + values.default = value + try: + values.default = int(values.default) + except:{} + elif name == '__enum_prefix__': + values.prefix = value + values.cleanPrefix = re.sub(r'[^\w_]', '_', value) + elif name == '__string_noprefix__': + values.supportNoPrefixForStrings = value.lower() == 'true' + elif name == '__tostring_noprefix__': + values.toStringNoPrefix = value.lower() == 'true' + elif name == '__const_shortcuts__': + values.constShortcuts = value.lower() == 'true' + else: + valParts = value.split(',') + try: + value = int(valParts[0]) + except:{} + names=name.split(',') + toStringVal = len(valParts) > 1 and valParts[1] or names[0] + values.items.append(Bunch(names=names, value=value, + toString=toStringVal)) + + + def cmpValues(x, y): + if x.value < y.value: + return -1 + elif x.value == y.value: + return 0 + return 1 + + try: + values.items = sorted(values.items, cmp=cmpValues) + except:{} + + if values.default is not None: + for item in values.items: + if values.default == item.value: + values.default = ''.join([values.cleanPrefix, item.names[0]]) + break + if type(values.default) != str: + values.default = values.items[0].value + + s.write(""" +/*! + * \struct %s + * + * Enumeration used to represent %ss + */\n""" % (enum, enum)) + s.write('struct %s\n{\n' % enum) + s.write(' //! The enumerations allowed\n') + s.write(' enum\n {\n') + for (i, item) in enumerate(values.items): + if item.value is not None: + s.write(' %s%s = %s' % (values.cleanPrefix, item.names[0], item.value)) + else: + s.write(' %s%s' % (values.cleanPrefix, item.names[0])) + if i < len(values.items) - 1: + s.write(',') + s.write('\n') + s.write(' };\n\n') + + s.write(' //! Default constructor\n') + s.write(' %s(){ value = %s; }\n\n' % (enum, values.default)) + + s.write(' //! string constructor\n') + s.write(' %s(std::string s)\n {\n' % enum) + i = 0 + for item in values.items: + for n in item.names: + names = ['%s%s' % (values.cleanPrefix, n)] + if values.supportNoPrefixForStrings: + names.append(n) + if values.prefix != values.cleanPrefix: + names.append('%s%s' % (values.prefix, n)) + for n in names: + s.write(' %sif (s == "%s")\n value = %s%s;\n' % (i > 0 and 'else ' or '', + n, values.cleanPrefix, item.names[0])) + i += 1 + s.write(' else\n throw except::InvalidFormatException(Ctxt(FmtX("Invalid enum value: %s", s.c_str())));\n') + s.write(' }\n\n') + + s.write(' //! int constructor\n') + s.write(' %s(int i)\n {\n switch(i)\n {\n' % enum) + idx = 0 + for (i, item) in enumerate(values.items): + if item.value is not None: + idx = item.value + s.write(' case %s:\n value = %s%s;\n break;\n' % (idx, values.cleanPrefix, item.names[0])) + try: + idx += 1 + except:{} + s.write(' default:\n throw except::InvalidFormatException(Ctxt(FmtX("Invalid enum value: %d", i)));\n') + s.write(' }\n }\n\n') + + s.write(' //! destructor\n') + s.write(' ~%s(){}\n\n' % enum) + + s.write(' //! Returns string representation of the value\n') + s.write(' std::string toString() const\n {\n switch(value)\n {\n') + idx = 0 + for (i, item) in enumerate(values.items): + if item.value is not None: + idx = item.value + if values.toStringNoPrefix: + s.write(' case %s:\n return std::string("%s");\n' % (idx, item.toString)) + else: + s.write(' case %s:\n return std::string("%s%s");\n' % (idx, values.prefix, item.toString)) + try: + idx += 1 + except:{} + s.write(' default:\n throw except::InvalidFormatException(Ctxt(FmtX("Invalid enum value: %d", value)));\n') + s.write(' }\n }\n\n') + + s.write(' //! assignment operator\n') + s.write(' %s& operator=(const %s& o)\n {\n' % (enum, enum)) + s.write(' if (&o != this)\n {\n value = o.value;\n }\n') + s.write(' return *this;\n }\n\n') + + s.write(' bool operator==(const %s& o) const { return value == o.value; }\n' % enum) + s.write(' bool operator!=(const %s& o) const { return value != o.value; }\n' % enum) + s.write(' bool operator==(const int& o) const { return value == o; }\n') + s.write(' bool operator!=(const int& o) const { return value != o; }\n') + s.write(' %s& operator=(const int& o) { value = o; return *this; }\n' % enum) + s.write(' bool operator<(const %s& o) const { return value < o.value; }\n' % enum) + s.write(' bool operator>(const %s& o) const { return value > o.value; }\n' % enum) + s.write(' bool operator<=(const %s& o) const { return value <= o.value; }\n' % enum) + s.write(' bool operator>=(const %s& o) const { return value >= o.value; }\n' % enum) + s.write(' operator int() const { return value; }\n') + s.write(' operator std::string() const { return toString(); }\n\n') + s.write(' static size_t size() { return %d; }\n\n' % len(values.items)) + s.write(' int value;\n\n') + s.write('};\n\n') + + if values.constShortcuts: + for (i, item) in enumerate(values.items): + s.write('const %s %s%s(%s::%s%s);\n' % (enum, values.cleanPrefix, item.names[0], + enum, values.cleanPrefix, item.names[0])) + s.write('\n') + +# print('template<> %s Init::undefined<%s>();' % (enum, enum)) +# print('template<> %s Init::undefined<%s>()\n{\n return %s::NOT_SET;\n}\n' % (enum, enum, enum)) + + return s.getvalue() + +if __name__ == '__main__': + from optparse import OptionParser + parser = OptionParser(usage="usage: %prog [options] FILE [OUTPUT]") + parser.add_option("-t", "--template", dest='template', action='store', + help="Specify the template file to use") + (options, args) = parser.parse_args() + if len(args) < 1: + parser.print_help() + sys.exit(1) + + import re, datetime + code = makeEnums(args[0]) + code += '\n// code auto-generated %s' % datetime.datetime.now() + + if options.template: + f = open(options.template) + template = f.read() + f.close() + template = re.sub(r'[$][{]CODE[}]', r'%s' % code, template) + else: + template = code + + if len(args) > 1: + f = open(args[1], 'w') + f.write(template) + f.close() + else: + print(template) + diff --git a/modules/build/swig.py b/modules/build/swig.py new file mode 100644 index 000000000..dffa9c9ec --- /dev/null +++ b/modules/build/swig.py @@ -0,0 +1,205 @@ +#! /usr/bin/env python +# encoding: UTF-8 +# Petar Forai +# Thomas Nagy 2008-2010 (ita) + +import re +from waflib import Task, Utils, Logs, Options +from waflib.TaskGen import extension, feature, after_method +from waflib.Configure import conf +from waflib.Tools import c_preproc + +""" +tasks have to be added dynamically: +- swig interface files may be created at runtime +- the module name may be unknown in advance +""" + +SWIG_EXTS = ['.swig', '.i'] + +re_module = re.compile('%module(?:\s*\(.*\))?\s+(.+)', re.M) + +re_1 = re.compile(r'^%module.*?\s+([\w]+)\s*?$', re.M) +re_2 = re.compile('%include "(.*)"', re.M) +re_3 = re.compile('#include "(.*)"', re.M) + +class swig(Task.Task): + color = 'BLUE' + run_str = '${SWIG} ${SWIGFLAGS} ${SWIGPATH_ST:INCPATHS} ${DEFINES_ST:DEFINES} ${SRC}' + ext_out = ['.h'] # might produce .h files although it is not mandatory + + def runnable_status(self): + for t in self.run_after: + if not t.hasrun: + return Task.ASK_LATER + + if not getattr(self, 'init_outputs', None): + self.init_outputs = True + if not getattr(self, 'module', None): + # search the module name + txt = self.inputs[0].read() + m = re_module.search(txt) + if not m: + raise ValueError("could not find the swig module name") + self.module = m.group(1) + + swig_c(self) + + # add the language-specific output files as nodes + # call funs in the dict swig_langs + for x in self.env['SWIGFLAGS']: + # obtain the language + x = x[1:] + try: + fun = swig_langs[x] + except KeyError: + pass + else: + fun(self) + + return super(swig, self).runnable_status() + + def post_run(self): + if self.swig_install_fun is not None: + self.swig_install_fun(self) + + super(swig, self).post_run() + + def scan(self): + "scan for swig dependencies, climb the .i files" + env = self.env + + lst_src = [] + + seen = [] + to_see = [self.inputs[0]] + + while to_see: + node = to_see.pop(0) + if node in seen: + continue + seen.append(node) + lst_src.append(node) + + # read the file + code = node.read() + code = c_preproc.re_nl.sub('', code) + code = c_preproc.re_cpp.sub(c_preproc.repl, code) + + # find .i files and project headers + names = re_2.findall(code) + re_3.findall(code) + for n in names: + for d in self.generator.includes_nodes + [node.parent]: + u = d.find_resource(n) + if u: + to_see.append(u) + break + else: + Logs.warn('could not find %r' % n) + + return (lst_src, []) + +# provide additional language processing +swig_langs = {} +def swigf(fun): + swig_langs[fun.__name__.replace('swig_', '')] = fun +swig.swigf = swigf + +def swig_c(self): + ext = '.swigwrap_%d.c' % self.generator.idx + flags = self.env['SWIGFLAGS'] + if '-c++' in flags: + ext += 'xx' + out_node = self.inputs[0].parent.find_or_declare(self.module + ext) + + if '-c++' in flags: + c_tsk = self.generator.cxx_hook(out_node) + else: + c_tsk = self.generator.c_hook(out_node) + + c_tsk.set_run_after(self) + + ge = self.generator.bld.producer + ge.outstanding.insert(0, c_tsk) + ge.total += 1 + + try: + ltask = self.generator.link_task + except AttributeError: + pass + else: + ltask.set_run_after(c_tsk) + ltask.inputs.append(c_tsk.outputs[0]) + + self.outputs.append(out_node) + + if not '-o' in self.env['SWIGFLAGS']: + self.env.append_value('SWIGFLAGS', ['-o', self.outputs[0].abspath()]) + +@swigf +def swig_python(tsk): + tsk.set_outputs(tsk.inputs[0].parent.find_or_declare(tsk.module + '.py')) + +@swigf +def swig_ocaml(tsk): + tsk.set_outputs(tsk.inputs[0].parent.find_or_declare(tsk.module + '.ml')) + tsk.set_outputs(tsk.inputs[0].parent.find_or_declare(tsk.module + '.mli')) + +@extension(*SWIG_EXTS) +def i_file(self, node): + # the task instance + tsk = self.create_task('swig') + tsk.set_inputs(node) + tsk.module = getattr(self, 'swig_module', None) + + flags = self.to_list(getattr(self, 'swig_flags', [])) + tsk.env.append_value('SWIGFLAGS', flags) + + tsk.swig_install_fun = getattr(self, 'swig_install_fun', None) + + # looks like this is causing problems + #if not '-outdir' in flags: + # tsk.env.append_value('SWIGFLAGS', ['-outdir', node.parent.abspath()]) + +@conf +def check_swig_version(self, minver=None): + """Check for a minimum swig version like conf.check_swig_version('1.3.28') + or conf.check_swig_version((1,3,28)) """ + reg_swig = re.compile(r'SWIG Version\s(.*)', re.M) + swig_out = self.cmd_and_log('"%s" -version' % self.env['SWIG']) + + swigver = [int(s) for s in reg_swig.findall(swig_out)[0].split('.')] + if isinstance(minver, basestring): + minver = [int(s) for s in minver.split(".")] + if isinstance(minver, tuple): + minver = [int(s) for s in minver] + result = (minver is None) or (minver[:3] <= swigver[:3]) + swigver_full = '.'.join(map(str, swigver)) + if result: + self.env['SWIG_VERSION'] = swigver_full + minver_str = minver and '.'.join(map(str, minver)) + if minver is None: + self.msg('swig version', swigver_full) + else: + self.msg('swig version >= %s' % (minver_str,), result, option=swigver_full) + return result + +def options(opt): + opt.add_option('--enable-swig', action='store_true', dest='swig', + help='Disable swig', default=False) + opt.add_option('--disable-swig', action='store_false', dest='swig', + help='Disable swig') + opt.add_option('--swig-version', action='store', dest='swigver', + default=None, help='Specify the minimum swig version') + opt.add_option('--require-swig', action='store_true', dest='require_swig', + help='Require swig (configure option)', default=False) + +def configure(conf): + if Options.options.swig: + swig = conf.find_program('swig', var='SWIG', mandatory=Options.options.require_swig) + if not swig: return + swigver = Options.options.swigver + if swigver: + swigver = map(int, swigver.split('.')) + conf.check_swig_version(minver=swigver) + conf.env.SWIGPATH_ST = '-I%s' diff --git a/modules/build/waf b/modules/build/waf new file mode 100755 index 000000000..d26b50054 Binary files /dev/null and b/modules/build/waf differ diff --git a/modules/c++/cli/include/cli/Argument.h b/modules/c++/cli/include/cli/Argument.h new file mode 100644 index 000000000..ea80d7450 --- /dev/null +++ b/modules/c++/cli/include/cli/Argument.h @@ -0,0 +1,123 @@ +/* ========================================================================= + * This file is part of cli-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * cli-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __CLI_ARGUMENT_H__ +#define __CLI_ARGUMENT_H__ + +#include +#include "cli/Value.h" + +namespace cli +{ + +enum Action +{ + STORE, STORE_TRUE, STORE_FALSE, STORE_CONST, SUB_OPTIONS, VERSION +}; + +// forward declaration +class ArgumentParser; + +/** + * An individual argument describes one entity from the command line. + * + * TODO: add support for case insensitive or standardizing choices/parsing + */ +class Argument +{ +public: + + ~Argument(); + + Argument* addFlag(std::string flag); + Argument* setAction(Action action); + Argument* setMinArgs(int num); + Argument* setMaxArgs(int num); + Argument* setDefault(Value* val, bool own = false); + Argument* setChoices(std::vector choices); + Argument* addChoice(std::string choice); + Argument* setHelp(std::string help); + Argument* setMetavar(std::string metavar); + Argument* setDestination(std::string dest); + Argument* setConst(Value* val, bool own = false); + Argument* setRequired(bool flag); + Argument* setShowsHelp(bool flag); + + template + Argument* setConst(const T val) + { + setConst(new Value(val), true); + return this; + } + + template + Argument* setDefault(const T val) + { + setDefault(new Value(val), true); + return this; + } + + inline const std::string& getName() const { return mName; } + inline const std::vector& getShortFlags() const { return mShortFlags; } + inline const std::vector& getLongFlags() const { return mLongFlags; } + inline Action getAction() const { return mAction; } + inline int getMinArgs() const { return mMinArgs; } + inline int getMaxArgs() const { return mMaxArgs; } + inline const Value* getDefault() const { return mDefaultValue; } + inline const std::vector& getChoices() const { return mChoices; } + inline bool isRequired() const { return mRequired; } + inline const std::string& getHelp() const { return mHelp; } + inline const std::string& getMetavar() const { return mMetavar; } + inline const std::string& getDestination() const { return mDestination; } + inline const Value* getConst() { return mConstValue; } + inline const bool showsHelp() { return mShowsHelp; } + + std::string getVariable() const; + bool isPositional() const; + +protected: + std::string mName; + std::vector mShortFlags; + std::vector mLongFlags; + Action mAction; + int mMinArgs; + int mMaxArgs; + Value* mDefaultValue; + bool mOwnDefault; + std::vector mChoices; + std::string mHelp; + std::string mMetavar; + std::string mDestination; + Value* mConstValue; + bool mOwnConst; + bool mRequired; + bool mShowsHelp; + ArgumentParser* mParser; + + friend class ArgumentParser; + Argument(std::string nameOrFlags, ArgumentParser* parser); + + std::string validateFlag(std::string flag) const; +}; + +} +#endif diff --git a/modules/c++/cli/include/cli/ArgumentParser.h b/modules/c++/cli/include/cli/ArgumentParser.h new file mode 100644 index 000000000..de65fefa7 --- /dev/null +++ b/modules/c++/cli/include/cli/ArgumentParser.h @@ -0,0 +1,137 @@ +/* ========================================================================= + * This file is part of cli-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * cli-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __CLI_ARGUMENT_PARSER_H__ +#define __CLI_ARGUMENT_PARSER_H__ + +#include +#include +#include "cli/Argument.h" +#include "cli/Results.h" + +namespace cli +{ + +enum +{ + EXIT_USAGE = 1, EXIT_VERSION = 2 +}; + +class ArgumentParser +{ +public: + ArgumentParser(); + ~ArgumentParser(); + + /** + * Shortcut for adding an argument. Returns the newly created argument. + */ + Argument* addArgument(std::string nameOrFlags, std::string help = "", + cli::Action action = cli::STORE, + std::string destination = "", + std::string metavar = "", + int minArgs = -1, int maxArgs = -1, + bool required = false); + + /** + * Text to display before the argument help + */ + ArgumentParser& setDescription(const std::string description); + + /** + * Text to display before the usage + */ + ArgumentParser& setProlog(const std::string prolog); + + /** + * Text to display after the argument help + */ + ArgumentParser& setEpilog(const std::string epilog); + + /** + * The program usage. This is generated by default. + */ + ArgumentParser& setUsage(const std::string usage); + + /** + * Enable the help option (on by default) + */ + ArgumentParser& enableHelp(bool flag); + + /** + * Set the name of the program (default is argv[0] + */ + ArgumentParser& setProgram(const std::string program); + + /** + * Prints the help and optionally exits. + */ + void printHelp(std::ostream& out = std::cerr, bool andExit = false) const; + + /** + * Prints the usage and optionally exits. + */ + void printUsage(std::ostream& out = std::cerr, bool andExit = false, + const std::string message = "") const; + + /** + * Parses the given arguments + */ + Results* parse(int argc, const char** argv); + + /** + * Parses the given arguments + */ + Results* parse(int argc, char** argv) + { + return parse(argc, const_cast(argv)); + } + + /** + * Parses the arguments. args[0] is NOT used as the program name, so you + * will need to specify it explicitly using setProgramName(). + */ + Results* parse(const std::vector& args); + +protected: + friend class Argument; + + std::vector mArgs; + std::string mDescription; + std::string mProlog; + std::string mEpilog; + std::string mUsage; + std::string mProgram; + bool mHelpEnabled; + char mPrefixChar; + + void parseError(const std::string& msg); + void processFlags(std::vector& posFlags, std::vector< + std::string>& opFlags, std::vector&posHelps, + std::vector&opHelps, + std::vector&opUsage, + std::vector&posUsage, + size_t& maxFlagsWidth) const; +}; + +} +#endif diff --git a/modules/c++/cli/include/cli/Results.h b/modules/c++/cli/include/cli/Results.h new file mode 100644 index 000000000..584cbf3b5 --- /dev/null +++ b/modules/c++/cli/include/cli/Results.h @@ -0,0 +1,149 @@ +/* ========================================================================= + * This file is part of cli-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * cli-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __CLI_RESULTS_H__ +#define __CLI_RESULTS_H__ + +#include +#include "cli/Value.h" + +namespace cli +{ + +class Results +{ +protected: + typedef std::map ValueStorage_T; + typedef ValueStorage_T::iterator ValueIter_T; + typedef ValueStorage_T::const_iterator ConstValueIter_T; + typedef std::map ResultsStorage_T; + typedef ResultsStorage_T::iterator ResultsIter_T; + typedef ResultsStorage_T::const_iterator ConstResultsIter_T; + +public: + Results() + { + } + ~Results() + { + destroy(); + } + + bool hasValue(const std::string& key) const + { + return mValues.find(key) != mValues.end(); + } + + bool hasSubResults(const std::string& key) const + { + return mResults.find(key) != mResults.end(); + } + + cli::Value* operator[](const std::string& key) const + throw (except::NoSuchKeyException) + { + return getValue(key); + } + + cli::Value* getValue(const std::string& key) const + throw (except::NoSuchKeyException) + { + ConstValueIter_T p = mValues.find(key); + if (p == mValues.end()) + throw except::NoSuchKeyException(Ctxt(key)); + return p->second; + } + + template + T get(const std::string& key, unsigned int index = 0) const + throw (except::NoSuchKeyException) + { + return getValue(key)->get(index); + } + + template + T operator()(const std::string& key, unsigned int index = 0) const + throw (except::NoSuchKeyException) + { + return get(key, index); + } + + cli::Results* getSubResults(const std::string& key) const + throw (except::NoSuchKeyException) + { + ConstResultsIter_T p = mResults.find(key); + if (p == mResults.end()) + throw except::NoSuchKeyException(Ctxt(key)); + return p->second; + } + + typedef ValueStorage_T::iterator iterator; + typedef ValueStorage_T::const_iterator const_iterator; + + iterator begin() { return mValues.begin(); } + const_iterator begin() const { return mValues.begin(); } + iterator end() { return mValues.end(); } + const_iterator end() const { return mValues.end(); } + +protected: + ValueStorage_T mValues; + ResultsStorage_T mResults; + + void destroy() + { + for (ValueIter_T it = mValues.begin(), end = mValues.end(); it != end; ++it) + delete it->second; + for (ResultsIter_T it = mResults.begin(), end = mResults.end(); it + != end; ++it) + delete it->second; + mValues.clear(); + mResults.clear(); + } + + friend class ArgumentParser; + + void put(const std::string& key, cli::Value *value) + { + if (hasValue(key)) + { + cli::Value* existing = getValue(key); + if (existing != value) + delete getValue(key); + } + mValues[key] = value; + } + + void put(const std::string& key, cli::Results *results) + { + if (hasSubResults(key)) + { + cli::Results *existing = getSubResults(key); + if (existing != results) + delete existing; + } + mResults[key] = results; + } +}; + +} + +#endif diff --git a/modules/c++/cli/include/cli/Value.h b/modules/c++/cli/include/cli/Value.h new file mode 100644 index 000000000..83fcd0ace --- /dev/null +++ b/modules/c++/cli/include/cli/Value.h @@ -0,0 +1,162 @@ +/* ========================================================================= + * This file is part of cli-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * cli-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __CLI_VALUE_H__ +#define __CLI_VALUE_H__ + +#include +#include +#include + +namespace cli +{ + +/** + * The Value class provides access to one or more actual values. + * It provides index-based access to parameters. + */ +class Value +{ +public: + Value() + { + } + + template + explicit Value(std::vector value) + { + setContainer(value); + } + + template + Value(T value) + { + set(value); + } + + template + Value(T* value, size_t size, bool own = false) + { + set(value, size, own); + } + + ~Value() + { + cleanup(); + } + + template + void set(T value) + { + cleanup(); + mValues.push_back(str::toString(value)); + } + + template + void set(T* value, size_t size, bool own = false) + { + cleanup(); + mValues.resize(size); + for (size_t i = 0; i < size; ++i) + mValues[i] = str::toString(value[i]); + if (own) + delete[] value; + } + + template + void setContainer(const std::vector& c) + { + cleanup(); + std::copy(c.begin(), c.end(), std::back_inserter(mValues)); + } + + template + T operator [](unsigned int index) const + { + return at(index); + } + + template + T at(unsigned int index = 0) const + { + if (index >= mValues.size()) + throw except::IndexOutOfRangeException( + Ctxt( + FmtX( + "Invalid index: %d", + index))); + return str::toType(mValues[index]); + } + + template + T get(unsigned int index = 0) const + { + return at(index); + } + + template + void add(T val) + { + mValues.push_back(str::toString(val)); + } + + /** + * Returns the size of the value. + */ + unsigned int size() const + { + return mValues.size(); + } + + Value* clone() const + { + return new Value(mValues); + } + + std::string toString() const + { + if (mValues.size() == 1) + return mValues[0]; + std::ostringstream s; + s << "[" << str::join(mValues, ", ") << "]"; + return s.str(); + } + + typedef std::vector::iterator iterator; + typedef std::vector::const_iterator const_iterator; + + iterator begin() { return mValues.begin(); } + const_iterator begin() const { return mValues.begin(); } + iterator end() { return mValues.end(); } + const_iterator end() const { return mValues.end(); } + +protected: + std::vector mValues; + + void cleanup() + { + mValues.clear(); + } +}; + +} +#endif diff --git a/modules/c++/cli/include/import/cli.h b/modules/c++/cli/include/import/cli.h new file mode 100644 index 000000000..f6db1e837 --- /dev/null +++ b/modules/c++/cli/include/import/cli.h @@ -0,0 +1,32 @@ +/* ========================================================================= + * This file is part of cli-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * cli-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __IMPORT_CLI_H__ +#define __IMPORT_CLI_H__ + +#include "cli/Argument.h" +#include "cli/ArgumentParser.h" +#include "cli/Results.h" +#include "cli/Value.h" + + +#endif diff --git a/modules/c++/cli/source/Argument.cpp b/modules/c++/cli/source/Argument.cpp new file mode 100644 index 000000000..be9beb963 --- /dev/null +++ b/modules/c++/cli/source/Argument.cpp @@ -0,0 +1,160 @@ +/* ========================================================================= + * This file is part of cli-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * cli-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include "cli/Argument.h" +#include "cli/ArgumentParser.h" +#include + +cli::Argument::Argument(std::string nameOrFlags, cli::ArgumentParser* parser) : + mAction(cli::STORE), mMinArgs(0), mMaxArgs(1), mDefaultValue(NULL), + mOwnDefault(false), mConstValue(NULL), mOwnConst(false), + mRequired(false), mShowsHelp(true), mParser(parser) +{ + std::vector < std::string > vars = str::split(nameOrFlags, " "); + if (vars.size() == 1 && !str::startsWith(vars[0], "-")) + mName = vars[0]; + else + { + for (std::vector::iterator it = vars.begin(); it + != vars.end(); ++it) + { + addFlag(*it); + } + } +} + +cli::Argument::~Argument() +{ + if (mOwnDefault && mDefaultValue) + delete mDefaultValue; + if (mOwnConst && mConstValue) + delete mConstValue; +} + +cli::Argument* cli::Argument::addFlag(std::string flag) +{ + char p = mParser->mPrefixChar; + std::string p2 = FmtX("%c%c", p, p); + if (flag.size() > 2 && str::startsWith(flag, p2) && flag[2] != p) + mLongFlags.push_back(validateFlag(flag.substr(2))); + else if (flag.size() > 1 && flag[0] == p && flag[1] != p) + mShortFlags.push_back(validateFlag(flag.substr(1))); + return this; +} +std::string cli::Argument::validateFlag(std::string flag) const +{ + const static std::string idChars = + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ012345789-_"; + std::string firstChar(flag.substr(0, 1)); + std::string rest = flag.substr(1); + if ((!str::isAlphanumeric(firstChar) && firstChar[0] != '_') + || (!str::containsOnly(rest, idChars))) + throw except::Exception(Ctxt("invalid flag")); + return flag; +} + +cli::Argument* cli::Argument::setAction(cli::Action action) +{ + mAction = action; + if (action == cli::STORE_TRUE || action == cli::STORE_FALSE || action + == cli::STORE_CONST || action == cli::VERSION) + { + // the flag, const or version are stored as the single argument + setMinArgs(1); + setMaxArgs(1); + } + return this; +} +cli::Argument* cli::Argument::setMinArgs(int num) +{ + mMinArgs = num; + return this; +} +cli::Argument* cli::Argument::setMaxArgs(int num) +{ + mMaxArgs = num; + return this; +} +cli::Argument* cli::Argument::setDefault(Value* val, bool own) +{ + mDefaultValue = val; + mOwnDefault = own; + return this; +} +cli::Argument* cli::Argument::setChoices(std::vector choices) +{ + mChoices.clear(); + mChoices = choices; + return this; +} +cli::Argument* cli::Argument::addChoice(std::string choice) +{ + mChoices.push_back(choice); + return this; +} +cli::Argument* cli::Argument::setHelp(std::string help) +{ + mHelp = help; + return this; +} +cli::Argument* cli::Argument::setMetavar(std::string metavar) +{ + mMetavar = metavar; + return this; +} +cli::Argument* cli::Argument::setDestination(std::string dest) +{ + mDestination = dest; + return this; +} +cli::Argument* cli::Argument::setConst(Value* val, bool own) +{ + mConstValue = val; + mOwnConst = own; + return this; +} +cli::Argument* cli::Argument::setRequired(bool flag) +{ + mRequired = flag; + return this; +} +cli::Argument* cli::Argument::setShowsHelp(bool flag) +{ + mShowsHelp = flag; + return this; +} + +std::string cli::Argument::getVariable() const +{ + if (!mDestination.empty()) + return mDestination; + if (!mName.empty()) + return mName; + if (!mLongFlags.empty()) + return mLongFlags[0]; + return mShortFlags[0]; +} + +bool cli::Argument::isPositional() const +{ + return mShortFlags.empty() && mLongFlags.empty(); +} diff --git a/modules/c++/cli/source/ArgumentParser.cpp b/modules/c++/cli/source/ArgumentParser.cpp new file mode 100644 index 000000000..be2241591 --- /dev/null +++ b/modules/c++/cli/source/ArgumentParser.cpp @@ -0,0 +1,781 @@ +/* ========================================================================= + * This file is part of cli-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * cli-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include "cli/ArgumentParser.h" +#include + +#define _MAX_ARG_LINE_LEN 21 + +namespace cli +{ +void _writeArgumentHelp(std::ostream& out, const std::string heading, + size_t maxFlagsWidth, + const std::vector& flags, + const std::vector& helps) +{ + std::ostringstream s; + out << heading << std::endl; + for (size_t i = 0, num = flags.size(); i < num; ++i) + { + s.str(""); + std::string flag = flags[i]; + std::string help = helps[i]; + if (flag.size() <= maxFlagsWidth) + { + s << " "; + s.width(maxFlagsWidth + 1); + s << std::left << flag; + s.width(0); + s << help; + out << s.str() << std::endl; + } + else + { + s << " "; + s << flag; + out << s.str() << std::endl; + s.str(""); + s.width(maxFlagsWidth + 3); + s << " "; + s.width(0); + s << help; + out << s.str() << std::endl; + } + } +} +} + +cli::ArgumentParser::ArgumentParser() : + mHelpEnabled(true), mPrefixChar('-') +{ +} + +cli::ArgumentParser::~ArgumentParser() +{ + for (std::vector::iterator it = mArgs.begin(); it + != mArgs.end(); ++it) + if (*it) + delete *it; +} + +/** + * Shortcut for adding an argument + */ +cli::Argument* cli::ArgumentParser::addArgument(std::string nameOrFlags, + std::string help, + cli::Action action, + std::string dest, + std::string metavar, + int minArgs, int maxArgs, + bool required) +{ + cli::Argument *arg = new cli::Argument(nameOrFlags, this); + + if (arg->isPositional()) + { + action = cli::STORE; + // if it is positional and a min args is supplied, require it + if (minArgs > 0) + required = true; + } + + switch (action) + { + case cli::STORE: + case cli::SUB_OPTIONS: + if (minArgs < 0) + { + minArgs = 1; + maxArgs = 1; + } + break; + case cli::STORE_TRUE: + case cli::STORE_FALSE: + case cli::STORE_CONST: + case cli::VERSION: + minArgs = 1; + maxArgs = 1; + break; + } + + arg->setMinArgs(minArgs); + arg->setMaxArgs(maxArgs); + arg->setAction(action); + arg->setDestination(dest); + arg->setHelp(help); + arg->setMetavar(metavar); + arg->setRequired(required); + mArgs.push_back(arg); + return arg; +} + +cli::ArgumentParser& cli::ArgumentParser::setDescription(const std::string d) +{ + mDescription = d; + return *this; +} + +cli::ArgumentParser& cli::ArgumentParser::setProlog(const std::string prolog) +{ + mProlog = prolog; + return *this; +} + +cli::ArgumentParser& cli::ArgumentParser::setEpilog(const std::string epilog) +{ + mEpilog = epilog; + return *this; +} + +cli::ArgumentParser& cli::ArgumentParser::setUsage(const std::string usage) +{ + mUsage = usage; + return *this; +} + +cli::ArgumentParser& cli::ArgumentParser::enableHelp(bool flag) +{ + mHelpEnabled = flag; + return *this; +} + +cli::ArgumentParser& cli::ArgumentParser::setProgram(const std::string program) +{ + mProgram = program; + return *this; +} + +void cli::ArgumentParser::printHelp(std::ostream& out, bool andExit) const +{ + std::vector posFlags, opFlags, posHelps, opHelps, opUsage, + posUsage; + size_t maxFlagsWidth = 0; + + processFlags(posFlags, opFlags, posHelps, opHelps, opUsage, posUsage, + maxFlagsWidth); + + if (!mProlog.empty()) + out << mProlog << std::endl << std::endl; + + out << "usage: "; + if (mUsage.empty()) + { + std::string progName = mProgram; + out << (progName.empty() ? "program" : progName); + if (!opUsage.empty()) + out << " " << str::join(opUsage, " "); + if (!posUsage.empty()) + out << " " << str::join(posUsage, " "); + out << std::endl; + } + else + out << mUsage << std::endl; + + if (!mDescription.empty()) + out << std::endl << mDescription << std::endl; + + if (posFlags.size() > 0) + { + out << std::endl; + cli::_writeArgumentHelp(out, "positional arguments:", maxFlagsWidth, + posFlags, posHelps); + } + + if (opFlags.size() > 0) + { + out << std::endl; + cli::_writeArgumentHelp(out, "optional arguments:", maxFlagsWidth, + opFlags, opHelps); + } + + if (!mEpilog.empty()) + out << std::endl << mEpilog << std::endl; + + if (andExit) + exit(cli::EXIT_USAGE); +} + +cli::Results* cli::ArgumentParser::parse(int argc, const char** argv) +{ + if (mProgram.empty() && argc > 0) + setProgram(std::string(argv[0])); + std::vector < std::string > args; + for (int i = 1; i < argc; ++i) + args.push_back(std::string(argv[i])); + return parse(args); +} +cli::Results* cli::ArgumentParser::parse(const std::vector& args) +{ + if (mProgram.empty()) + setProgram("program"); + + std::map shortFlags; + std::map longFlags; + std::map shortOptionsFlags; + std::map longOptionsFlags; + std::vector positionalArgs; + + // first, validate the arguments + for (std::vector::const_iterator it = mArgs.begin(); it + != mArgs.end(); ++it) + { + cli::Argument *arg = *it; + std::string argVar = arg->getVariable(); + + if (arg->isPositional()) + { + positionalArgs.push_back(arg); + } + else + { + const std::vector& argShortFlags = + arg->getShortFlags(); + const std::vector& argLongFlags = arg->getLongFlags(); + bool subOption = (arg->getAction() == cli::SUB_OPTIONS); + for (std::vector::const_iterator it = + argShortFlags.begin(); it != argShortFlags.end(); ++it) + { + std::string op = *it; + std::map& flagMap = + (subOption ? shortOptionsFlags : shortFlags); + if (flagMap.find(op) != flagMap.end()) + parseError(FmtX("Conflicting option: %c%s", mPrefixChar, + op.c_str())); + flagMap[op] = arg; + } + for (std::vector::const_iterator it = + argLongFlags.begin(); it != argLongFlags.end(); ++it) + { + std::string op = *it; + std::map& flagMap = + (subOption ? longOptionsFlags : longFlags); + if (flagMap.find(op) != flagMap.end()) + parseError(FmtX("Conflicting option: %c%c%s", mPrefixChar, + mPrefixChar, op.c_str())); + flagMap[op] = arg; + } + } + + } + + std::vector < std::string > explodedArgs; + // next, check for combined short options + for (size_t i = 0, s = args.size(); i < s; ++i) + { + std::string argStr = args[i]; + if (argStr.size() > 1 && argStr[0] == mPrefixChar && argStr[1] + != mPrefixChar) + { + std::string flag = argStr.substr(1); + if (shortFlags.find(flag) != shortFlags.end()) + { + explodedArgs.push_back(argStr); + } + else + { + // check for = + if (argStr.find("=") != std::string::npos) + { + std::vector < std::string > parts = str::split(argStr, "=", + 2); + std::copy(parts.begin(), parts.end(), + std::back_inserter(explodedArgs)); + } + else + { + // first, see if it is an extra option + std::vector < std::string > parts = str::split(argStr, ":", + 2); + if (parts.size() == 2) + { + explodedArgs.push_back(argStr); + } + else + { + // split up each char as separate options + // only the last will get any additional args + for (size_t j = 0, n = flag.size(); j < n; ++j) + { + std::string charFlag = flag.substr(j, 1); + std::ostringstream oss; + oss << mPrefixChar << charFlag; + explodedArgs.push_back(oss.str()); + } + } + } + } + } + else if (argStr.size() > 2 && argStr[0] == mPrefixChar && argStr[1] + == mPrefixChar) + { + // check for = + if (argStr.find("=") != std::string::npos) + { + std::vector < std::string > parts = str::split(argStr, "=", 2); + std::copy(parts.begin(), parts.end(), + std::back_inserter(explodedArgs)); + } + else + explodedArgs.push_back(argStr); + } + else + { + explodedArgs.push_back(argStr); + } + } + + cli::Results *results = new Results; + cli::Results *currentResults = NULL; + for (size_t i = 0, s = explodedArgs.size(); i < s; ++i) + { + currentResults = results; // set the pointer + std::string argStr = explodedArgs[i]; + cli::Argument *arg = NULL; + std::string optionsStr(""); + if (argStr.size() > 2 && argStr[0] == mPrefixChar && argStr[1] + == mPrefixChar) + { + std::string flag = argStr.substr(2); + if (longFlags.find(flag) != longFlags.end()) + { + arg = longFlags[flag]; + } + else if (mHelpEnabled && flag == "help") + { + printHelp(std::cerr, true); + } + else + { + // check if it's an options flag + std::vector < std::string > parts = str::split(flag, ":", 2); + if (parts.size() == 2 && longOptionsFlags.find(parts[0]) + != longOptionsFlags.end()) + { + arg = longOptionsFlags[parts[0]]; + optionsStr = parts[1]; + std::string argVar = arg->getVariable(); + if (!results->hasSubResults(argVar)) + results->put(argVar, new cli::Results); + currentResults = results->getSubResults(argVar); + } + else + { + throw except::Exception(Ctxt(FmtX("Invalid option: [%s]", + argStr.c_str()))); + } + } + } + else if (argStr.size() > 1 && argStr[0] == mPrefixChar && argStr[1] + != mPrefixChar) + { + std::string flag = argStr.substr(1); + if (shortFlags.find(flag) != shortFlags.end()) + { + arg = shortFlags[flag]; + } + else if (mHelpEnabled && flag == "h") + { + printHelp(std::cerr, true); + } + else + { + // check if it's an options flag + std::vector < std::string > parts = str::split(flag, ":", 2); + if (parts.size() == 2 && shortOptionsFlags.find(parts[0]) + != shortOptionsFlags.end()) + { + arg = shortOptionsFlags[parts[0]]; + optionsStr = parts[1]; + std::string argVar = arg->getVariable(); + if (!results->hasSubResults(argVar)) + results->put(argVar, new cli::Results); + currentResults = results->getSubResults(argVar); + } + else + { + throw except::Exception(Ctxt(FmtX("Invalid option: [%s]", + argStr.c_str()))); + } + } + } + + if (arg != NULL) + { + std::string argVar = arg->getVariable(); + switch (arg->getAction()) + { + case cli::STORE: + { + cli::Value + *v = + currentResults->hasValue(argVar) ? currentResults->getValue( + argVar) + : new cli::Value; + int maxArgs = arg->getMaxArgs(); + // risky, I know... + bool added = false; + while (i < s - 1) + { + std::string nextArg(explodedArgs[i + 1]); + if (nextArg.size() > 1 && nextArg[0] == mPrefixChar) + { + // it's another flag, so we break out + break; + } + if (maxArgs >= 0 && v->size() >= maxArgs) + { + // it's another positional argument, so we break out + break; + } + v->add(nextArg); + ++i; + added = true; + } + + if (!added) + parseError( + FmtX( + "option requires value or has exceeded its max: [%s]", + argVar.c_str())); + + currentResults->put(argVar, v); + break; + } + case cli::STORE_TRUE: + currentResults->put(argVar, new cli::Value(true)); + break; + case cli::STORE_FALSE: + currentResults->put(argVar, new cli::Value(false)); + break; + case cli::STORE_CONST: + { + const Value* constVal = arg->getConst(); + currentResults->put(argVar, constVal ? constVal->clone() : NULL); + break; + } + case cli::SUB_OPTIONS: + { + if (optionsStr.empty()) + parseError(FmtX("invalid sub option: [%s]", argVar.c_str())); + cli::Value + *v = + currentResults->hasValue(optionsStr) ? currentResults->getValue( + optionsStr) + : new cli::Value; + if (i < s - 1) + { + std::string nextArg = explodedArgs[i + 1]; + if (nextArg.size() > 1 && nextArg[0] == mPrefixChar) + { + // it's another flag + // this indicates the sub op is a bool + v->add(true); + } + else + { + v->add(nextArg); + ++i; + } + } + else + { + // this indicates the sub op is a bool + v->add(true); + } + currentResults->put(optionsStr, v); + break; + } + case cli::VERSION: + //TODO + break; + } + } + else + { + // it's a positional argument + cli::Value *lastPosVal = NULL; + for (std::vector::iterator it = + positionalArgs.begin(); it != positionalArgs.end(); ++it) + { + cli::Argument *posArg = *it; + std::string argVar = posArg->getVariable(); + int maxArgs = posArg->getMaxArgs(); + if (currentResults->hasValue(argVar)) + { + cli::Value *posVal = lastPosVal + = currentResults->getValue(argVar); + if (posVal->size() >= maxArgs) + continue; + break; + } + else if (maxArgs != 0) + { + lastPosVal = new cli::Value; + currentResults->put(argVar, lastPosVal); + break; + } + } + if (lastPosVal) + lastPosVal->add(argStr); + else + parseError("too many arguments"); + } + } + + // add the defaults + for (std::vector::const_iterator it = mArgs.begin(); it + != mArgs.end(); ++it) + { + cli::Argument *arg = *it; + std::string argMeta = arg->getMetavar(); + std::string argVar = arg->getVariable(); + std::string argId = arg->isPositional() && !argMeta.empty() ? argMeta + : argVar; + + if (!results->hasValue(argVar)) + { + const Value* defaultVal = arg->getDefault(); + if (defaultVal != NULL) + results->put(argVar, defaultVal->clone()); + else if (arg->getAction() == cli::STORE_FALSE) + results->put(argVar, new cli::Value(true)); + else if (arg->getAction() == cli::STORE_TRUE) + results->put(argVar, new cli::Value(false)); + else if (arg->isRequired()) + parseError(FmtX("missing required argument: [%s]", + argVar.c_str())); + } + + + // validate the argument value against the choices + // TODO: add option to make case sensitive + std::vector choices = arg->getChoices(); + if (!choices.empty()) + { + bool isValid = false; + std::string val = results->getValue(argVar)->toString(); + str::lower(val); + + for (int i = 0; i < choices.size(); i++) + { + std::string choice = choices[i]; + str::lower(choice); + if (str::containsOnly(val, choice)) + { + isValid = true; + break; + } + } + if (!isValid) + { + parseError(FmtX("invalid option for [%s]", argVar.c_str())); + } + } + + + // validate # of args + int minArgs = arg->getMinArgs(); + int maxArgs = arg->getMaxArgs(); + size_t numGiven = + results->hasValue(argVar) ? results->getValue(argVar)->size() + : 0; + + if (arg->isRequired() || numGiven > 0) + { + if (minArgs > 0 && numGiven < minArgs) + parseError(FmtX("not enough arguments, %d required: [%s]", + minArgs, argId.c_str())); + if (maxArgs >= 0 && numGiven > maxArgs) + parseError(FmtX("too many arguments, %d supported: [%s]", + maxArgs, argId.c_str())); + } + } + + return results; +} + +void cli::ArgumentParser::printUsage(std::ostream& out, bool andExit, + const std::string message) const +{ + out << "usage: "; + if (mUsage.empty()) + { + std::vector posFlags, opFlags, posHelps, opHelps, opUsage, + posUsage; + size_t maxFlagsWidth = 0; + + processFlags(posFlags, opFlags, posHelps, opHelps, opUsage, posUsage, + maxFlagsWidth); + + std::string progName = mProgram; + out << (progName.empty() ? "program" : progName); + if (!opUsage.empty()) + out << " " << str::join(opUsage, " "); + if (!posUsage.empty()) + out << " " << str::join(posUsage, " "); + } + else + out << mUsage; + if (!message.empty()) + out << std::endl << std::endl << message; + out << std::endl; + if (andExit) + exit(cli::EXIT_USAGE); +} + +void cli::ArgumentParser::parseError(const std::string& msg) +{ + std::ostringstream s; + s << "usage: "; + if (mUsage.empty()) + { + std::vector posFlags, opFlags, posHelps, opHelps, opUsage, + posUsage; + size_t maxFlagsWidth = 0; + + processFlags(posFlags, opFlags, posHelps, opHelps, opUsage, posUsage, + maxFlagsWidth); + + std::string progName = mProgram; + s << (progName.empty() ? "program" : progName); + if (!opUsage.empty()) + s << " " << str::join(opUsage, " "); + if (!posUsage.empty()) + s << " " << str::join(posUsage, " "); + } + else + s << mUsage; + s << "\n" << msg; + throw except::ParseException(s.str()); +} + +void cli::ArgumentParser::processFlags(std::vector& posFlags, + std::vector& opFlags, + std::vector&posHelps, + std::vector&opHelps, + std::vector&opUsage, + std::vector&posUsage, + size_t& maxFlagsWidth) const +{ + std::ostringstream s; + + if (mHelpEnabled) + { + std::string helpMsg = FmtX("%ch, %c%chelp", mPrefixChar, mPrefixChar, + mPrefixChar); + maxFlagsWidth = std::max(helpMsg.size(), maxFlagsWidth); + opFlags.push_back(helpMsg); + opHelps.push_back("show this help message and exit"); + } + + for (std::vector::const_iterator it = mArgs.begin(); it + != mArgs.end(); ++it) + { + cli::Argument *arg = *it; + const std::string& argName = arg->getName(); + const cli::Action& argAction = arg->getAction(); + const std::vector& argChoices = arg->getChoices(); + const std::string& argMetavar = arg->getMetavar(); + const std::string& argHelp = arg->getHelp(); + const cli::Value* defaultVal = arg->getDefault(); + + s.str(""); + s << argHelp; + if (defaultVal) + s << " (default: " << defaultVal->toString() << ")"; + std::string helpMsg = s.str(); + + s.str(""); + if (!argMetavar.empty()) + s << argMetavar; + else if (!argChoices.empty()) + s << "{" << str::join(argChoices, ",") << "}"; + std::string meta = s.str(); + + if (arg->isPositional()) + { + //positional argument + std::string op = meta.empty() ? argName : meta; + maxFlagsWidth = std::max(op.size(), maxFlagsWidth); + posFlags.push_back(op); + if (arg->showsHelp()) + { + posHelps.push_back(helpMsg); + posUsage.push_back(op); + } + } + else + { + std::vector < std::string > ops; + const std::vector& argShortFlags = + arg->getShortFlags(); + const std::vector& argLongFlags = arg->getLongFlags(); + for (size_t i = 0, n = argShortFlags.size(); i < n; ++i) + { + s.str(""); + s << mPrefixChar << argShortFlags[i]; + if (argAction == cli::SUB_OPTIONS) + { + if (meta.empty()) + s << ":ARG[=VALUE]"; + else + s << ":" << meta; + } + else if (!meta.empty()) + s << " " << meta; + ops.push_back(s.str()); + } + for (size_t i = 0, n = argLongFlags.size(); i < n; ++i) + { + s.str(""); + s << mPrefixChar << mPrefixChar << argLongFlags[i]; + if (argAction == cli::SUB_OPTIONS) + { + if (meta.empty()) + s << ":ARG[=VALUE]"; + else + s << ":" << meta; + } + else if (!meta.empty()) + s << " " << meta; + ops.push_back(s.str()); + } + if (!ops.empty()) + { + s.str(""); + s << "[" << ops[0] << "]"; + if (arg->showsHelp()) + opUsage.push_back(s.str()); + + std::string opMsg = str::join(ops, ", "); + maxFlagsWidth = std::max(opMsg.size(), maxFlagsWidth); + if (arg->showsHelp()) + { + opFlags.push_back(opMsg); + opHelps.push_back(helpMsg); + } + } + } + } + maxFlagsWidth = std::min(maxFlagsWidth, _MAX_ARG_LINE_LEN); +} + diff --git a/modules/c++/cli/unittests/test_cli.cpp b/modules/c++/cli/unittests/test_cli.cpp new file mode 100644 index 000000000..b9218c2b5 --- /dev/null +++ b/modules/c++/cli/unittests/test_cli.cpp @@ -0,0 +1,183 @@ +/* ========================================================================= + * This file is part of cli-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * cli-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include +#include "TestCase.h" + +TEST_CASE(testValue) +{ + cli::Value v("data"); + TEST_ASSERT_EQ("data", v.get()); + + v.set(3.14f); + TEST_ASSERT_ALMOST_EQ(3.14f, v.get()); + TEST_ASSERT_EQ(3, v.get()); + + float floats[10]; + std::string strings[10]; + for(int i = 0; i < 10; ++i) + { + floats[i] = 10.0f * i; + strings[i] = str::toString(i); + } + + // floats + v.set((float*)&floats, 10, false); + for(int i = 0; i < 10; ++i) + { + TEST_ASSERT_ALMOST_EQ(v.at(i), 10.0f * i); + } + TEST_ASSERT_EQ(v.size(), 10); + + // strings + v.set((std::string*)&strings, 10, false); + for(int i = 0; i < 10; ++i) + { + TEST_ASSERT_EQ(v.at(i), str::toString(i)); + } + TEST_ASSERT_EQ(v.size(), 10); +} + +TEST_CASE(testChoices) +{ + cli::ArgumentParser parser; + parser.setProgram("tester"); + parser.addArgument("-v --verbose", "Toggle verbose", cli::STORE_TRUE); + parser.addArgument("-t --type", "Specify a type to use", cli::STORE)->addChoice( + "type1")->addChoice("type2")->addChoice("type3"); + parser.addArgument("-m --many", "Specify a type to use", cli::STORE, "choices", "CHOICES", 0)->addChoice( + "type1")->addChoice("type2")->addChoice("type3"); + parser.addArgument("images", "Input images", cli::STORE); + parser.setDescription("This program is kind of pointless, but have fun!"); + parser.setProlog("========= (c) COPYRIGHT BANNER ========= "); + parser.setEpilog("And that's the usage of the program!"); + parser.printHelp(); + + std::auto_ptr results(parser.parse(str::split("-v", " "))); + TEST_ASSERT(results->hasValue("verbose")); + TEST_ASSERT(results->get("verbose", 0)); + + results.reset(parser.parse(str::split("", " "))); + TEST_ASSERT_EQ(results->get("verbose", 0), false); + + results.reset(parser.parse(str::split("-t type2", " "))); + TEST_ASSERT_EQ(results->get("type", 0), std::string("type2")); + + try + { + results.reset(parser.parse(str::split("-t type2 -t type1", " "))); + TEST_FAIL("Shouldn't allow multiple types"); + } + catch(except::Exception& ex) + { + } + results.reset(parser.parse(str::split("-t type2", " "))); + + results.reset(parser.parse(str::split("-m type2 --many type1 -m type3", " "))); +} + +TEST_CASE(testMultiple) +{ + cli::ArgumentParser parser; + parser.setProgram("tester"); + parser.addArgument("-v --verbose --loud -l", "Toggle verbose", cli::STORE_TRUE); + + std::auto_ptr results(parser.parse(str::split("-v"))); + TEST_ASSERT(results->hasValue("verbose")); + TEST_ASSERT(results->get("verbose")); + + results.reset(parser.parse(str::split("-l"))); + TEST_ASSERT(results->get("verbose")); + results.reset(parser.parse(str::split("--loud"))); + TEST_ASSERT(results->get("verbose")); + results.reset(parser.parse(str::split(""))); + TEST_ASSERT_FALSE(results->get("verbose")); +} + +TEST_CASE(testSubOptions) +{ + cli::ArgumentParser parser; + parser.setProgram("tester"); + parser.addArgument("-v --verbose", "Toggle verbose", cli::STORE_TRUE); + parser.addArgument("-c --config", "Specify a config file", cli::STORE); + parser.addArgument("-x --extra", "Extra options", cli::SUB_OPTIONS); + parser.addArgument("-c --config", "Config options", cli::SUB_OPTIONS); + parser.printHelp(); + + std::auto_ptr results(parser.parse(str::split("-x:special"))); + TEST_ASSERT(results->hasSubResults("extra")); + TEST_ASSERT(results->getSubResults("extra")->get("special")); + + results.reset(parser.parse(str::split("--extra:arg=something -x:arg2 1"))); + TEST_ASSERT(results->hasSubResults("extra")); + TEST_ASSERT_EQ(results->getSubResults("extra")->get("arg"), "something"); + TEST_ASSERT_EQ(results->getSubResults("extra")->get("arg2"), 1); + + results.reset(parser.parse(str::split("--config /path/to/file --config:flag1 -c:flag2=true --config:flag3 false"))); + TEST_ASSERT_EQ(results->get("config"), "/path/to/file"); + TEST_ASSERT(results->hasSubResults("config")); + TEST_ASSERT(results->getSubResults("config")->get("flag1")); + TEST_ASSERT(results->getSubResults("config")->get("flag2")); + TEST_ASSERT_FALSE(results->getSubResults("config")->get("flag3")); +} + +TEST_CASE(testIterate) +{ + cli::ArgumentParser parser; + parser.setProgram("tester"); + parser.addArgument("-v --verbose", "Toggle verbose", cli::STORE_TRUE); + parser.addArgument("-c --config", "Specify a config file", cli::STORE); + + std::auto_ptr + results(parser.parse(str::split("-v -c config.xml"))); + std::vector keys; + for(cli::Results::const_iterator it = results->begin(); it != results->end(); ++it) + keys.push_back(it->first); + TEST_ASSERT_EQ(keys.size(), 2); + // std::map returns keys in alphabetical order... + TEST_ASSERT_EQ(keys[0], "config"); + TEST_ASSERT_EQ(keys[1], "verbose"); +} + +TEST_CASE(testRequired) +{ + cli::ArgumentParser parser; + parser.setProgram("tester"); + parser.addArgument("-v --verbose", "Toggle verbose", cli::STORE_TRUE); + parser.addArgument("-c --config", "Specify a config file", cli::STORE)->setRequired(true); + + std::auto_ptr results; + TEST_EXCEPTION(results.reset(parser.parse(str::split("")))); + TEST_EXCEPTION(results.reset(parser.parse(str::split("-c")))); + results.reset(parser.parse(str::split("-c configFile"))); + TEST_ASSERT_EQ(results->get("config"), "configFile"); +} + +int main(int argc, char* argv[]) +{ + TEST_CHECK( testValue); + TEST_CHECK( testChoices); + TEST_CHECK( testMultiple); + TEST_CHECK( testSubOptions); + TEST_CHECK( testIterate); + TEST_CHECK( testRequired); +} diff --git a/modules/c++/cli/wscript b/modules/c++/cli/wscript new file mode 100644 index 000000000..5b710749a --- /dev/null +++ b/modules/c++/cli/wscript @@ -0,0 +1,9 @@ +NAME = 'cli' +MAINTAINER = 'jmrandol@users.sourceforge.net' +VERSION = '1.2' +MODULE_DEPS = 'sys' + +options = configure = distclean = lambda p: None + +def build(bld): + bld.module(**globals()) diff --git a/modules/c++/except/README.txt b/modules/c++/except/README.txt new file mode 100644 index 000000000..6deca82d2 --- /dev/null +++ b/modules/c++/except/README.txt @@ -0,0 +1,7 @@ +This library defines a set of exceptions, and errors, throwables which +can be caught and manipulated within the constructs of the C++ langaguge. + +When used in conjunction with the sys package, this library is a necessity, +and because of its simple, java-like exception hierarchy, it is easy to understand. + + diff --git a/modules/c++/except/include/except/Context.h b/modules/c++/except/include/except/Context.h new file mode 100644 index 000000000..3e62db389 --- /dev/null +++ b/modules/c++/except/include/except/Context.h @@ -0,0 +1,138 @@ +/* ========================================================================= + * This file is part of except-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * except-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __EXCEPT_CONTEXT_H__ +#define __EXCEPT_CONTEXT_H__ + +#include +#include + +/*! + * \file + * \brief defines a class that contains the information surrounding an + * exception or error. + */ +namespace except +{ + +/*! + * \class Context + * \brief The information surrounding an exception or error + * + * This class contains information such as the file, line, + * function and time + */ +class Context +{ +public: + + /*! + * Constructor + * \param message The message describing the exception + * \param time The system time when the error occurred. + * \param func The function where the error occured (not always available) + * \param file The file where the exception occurred + * \param line The line number where the exception occurred + */ + Context(const std::string& file, + int line, + const std::string& func, + const std::string& time, + const std::string& message) : mMessage(message), mTime(time), mFunc(func), + mFile(file), mLine(line) + {} + + /*! + * Copy constructor + * \param c The context to copy + */ + Context(const Context& c); + + /*! + * Assignment operator + * \param c The context to copy + */ + Context& operator=(const Context& c); + + /*! + * Get the message describing the exception that occurred + * \return The message + */ + const std::string& getMessage() const + { + return mMessage; + } + + /*! + * Get the system time + * \return The system time + */ + const std::string& getTime() const + { + return mTime; + } + + /*! + * Get the function where the exception occurred (may not be available + * \return The function signature + */ + const std::string& getFunction() const + { + return mFunc; + } + + /*! + * Get the file where the exception occurred + * \return The file + */ + const std::string& getFile() const + { + return mFile; + } + + /*! + * Get the line number + * \return The line number + */ + int getLine() const + { + return mLine; + } + + //! The name of the message the exception was thrown + std::string mMessage; + //! The date/time the exception was thrown + std::string mTime; + //! The name of the function the exception was thrown + std::string mFunc; + //! The name of the file the exception was thrown + std::string mFile; + //! The line number where the exception was thrown + int mLine; +}; + +} + +std::ostream& operator<< (std::ostream& os, const except::Context& c); + +#endif diff --git a/modules/c++/except/include/except/Error.h b/modules/c++/except/include/except/Error.h new file mode 100644 index 000000000..6390645d2 --- /dev/null +++ b/modules/c++/except/include/except/Error.h @@ -0,0 +1,123 @@ +/* ========================================================================= + * This file is part of except-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * except-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __EXCEPT_ERROR_H__ +#define __EXCEPT_ERROR_H__ + +/*! + * \file Error.h + * \brief Contains the classes to do with error handling + * + * An error is a throwable pertaining to rather serious errors + * i.e., ones that could cripple the system if handled improperly. + * For that reason, it is worth considering, upon designing a handler + * whether or not to simply abort the program upon receiving an error. + */ +#include "Throwable.h" + +/*! + * Useful macro for defining Exception classes + */ +#define DECLARE_EXTENDED_ERROR(_Name, _Base) \ + class _Name##Error : public _Base \ + { \ + public: \ + _Name##Error() : _Base(){} \ + _Name##Error(const except::Context& c) : _Base(c){} \ + _Name##Error(const std::string& msg) : _Base(msg){} \ + _Name##Error(const except::Throwable& t, const except::Context& c) : _Base(t, c){} \ + virtual ~_Name##Error(){} \ + virtual std::string getType() const{ return #_Name; } \ + }; + +#define DECLARE_ERROR(_Name) DECLARE_EXTENDED_ERROR(_Name, except::Error) + +namespace except +{ +/*! + * \class Error + * \brief Represents a serious unexpected occurrence during the program + * + * The error class is a representation of a throwable object, occurring + * under serious conditions. It may be undesirable to handle an error in + * the manner that you handle an exception. For this reason, the distinction is + * made + */ +class Error : public Throwable +{ +public: + /*! + * Default constructor + */ + Error() : + Throwable() + { + } + + /*! + * Constructor. Takes a Context + * \param c The Context + */ + Error(const Context& c) : + Throwable(c) + { + } + + /*! + * Constructor. Takes a message + * \param message The message + */ + Error(const std::string& message) : + Throwable(message) + { + } + + /*! + * Constructor. Takes an Throwable and a Context + * \param t The Throwable + * \param c The Context + */ + Error(const Throwable& t, const Context& c) : + Throwable(t, c) + { + } + + //! Destructor + virtual ~Error() + { + } + + virtual std::string getType() const + { + return "Error"; + } +}; + +/*! + * \class InvalidDerivedTypeError + * \brief Represents an invalid derived type error. + */ +DECLARE_ERROR(InvalidDerivedType) + +} + +#endif diff --git a/modules/c++/except/include/except/Exception.h b/modules/c++/except/include/except/Exception.h new file mode 100644 index 000000000..10b5380d9 --- /dev/null +++ b/modules/c++/except/include/except/Exception.h @@ -0,0 +1,208 @@ +/* ========================================================================= + * This file is part of except-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * except-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __EXCEPT_EXCEPTION_H__ +#define __EXCEPT_EXCEPTION_H__ + +/*! + * \file Exception.h + * \brief Contains the classes to do with exception handling. + * + * A Throwable has two possible classifications (according to java, and for our + * purposes, that is good enough): Errors and Exceptions. + * This class deals with the latter. + * + */ +#include +#include +#include "except/Throwable.h" + +/*! + * Useful macro for defining Exception classes + */ +#define DECLARE_EXTENDED_EXCEPTION(_Name, _Base) \ + class _Name##Exception : public _Base \ + { \ + public: \ + _Name##Exception() : _Base(){} \ + _Name##Exception(const except::Context& c) : _Base(c){} \ + _Name##Exception(const std::string& msg) : _Base(msg){} \ + _Name##Exception(const except::Throwable& t, const except::Context& c) : _Base(t, c){} \ + virtual ~_Name##Exception(){} \ + virtual std::string getType() const{ return #_Name"Exception"; } \ + }; + +#define DECLARE_EXCEPTION(_Name) DECLARE_EXTENDED_EXCEPTION(_Name, except::Exception) + +namespace except +{ + +/*! + * \class Exception + * \brief (typically non-fatal) throwable. + * + * This class is the base for all exceptions. + */ +class Exception : public Throwable +{ +public: + + /*! + * Constructor. + */ + Exception() : + Throwable() + { + } + + /*! + * Constructor. Takes a Context + * \param c The Context + */ + Exception(const Context& c) : + Throwable(c) + { + } + + /*! + * Constructor. Takes an Throwable and a Context + * \param t The Throwable + * \param c The Context + */ + Exception(const Throwable& t, const Context& c) : + Throwable(t, c) + { + } + + /*! + * Constructor. Takes a message + * \param message The message + */ + Exception(const std::string& message) : + Throwable(message) + { + } + + //! Destructor + virtual ~Exception() + { + } + + virtual std::string getType() const + { + return "Exception"; + } +}; + +/*! + * \class IOException + * \brief Throwable related to IO problems. + */ +DECLARE_EXCEPTION(IO) + +/*! + * \class FileNotFoundException + * \brief Throwable related to a file not found. + */ +DECLARE_EXTENDED_EXCEPTION(FileNotFound, except::IOException) + +/*! + * \class BadCastException + * \brief Exception for bad casting operations + */ +DECLARE_EXCEPTION(BadCast) + +/*! + * \class InvalidFormatException + * \brief Throwable related to an invalid file format. + */ +DECLARE_EXCEPTION(InvalidFormat) + +/*! + * \class IndexOutOfRangeException + * \brief Throwable related to an index being out of range. + */ +DECLARE_EXCEPTION(IndexOutOfRange) + +/*! + * \class OutOfMemoryException + * \brief Throwable related to memory allocation problems. + */ +DECLARE_EXCEPTION(OutOfMemory) + +/*! + * \class NullPointerReference + * \brief This is responsible for handling a null pointer ref/deref + * + * This class is currently treated as an exception, meaning that its + * behavior is not necessarily fatal. + */ +DECLARE_EXCEPTION(NullPointerReference) +//! For backwards-compatibility +typedef NullPointerReferenceException NullPointerReference; + +/*! + * \class NoSuchKeyException + * \brief Throwable related to unknown keys. + */ +DECLARE_EXCEPTION(NoSuchKey) + +/*! + * \class NoSuchReferenceException + * \brief Throwable related to unknown references. + */ +DECLARE_EXCEPTION(NoSuchReference) + +/*! + * \class KeyAlreadyExistsException + * \brief Throwable related to duplicate keys. + */ +DECLARE_EXCEPTION(KeyAlreadyExists) + +/*! + * \class NotImplementedException + * \brief Throwable related to code not being implemented yet. + */ +DECLARE_EXCEPTION(NotImplemented) + +/*! + * \class InvalidArgumentException + * \brief Throwable related to an invalid argument being passed. + */ +DECLARE_EXCEPTION(InvalidArgument) + +/*! + * \class SerializationException + * \brief Throwable related to failing to serialize/deserialize data. + */ +DECLARE_EXTENDED_EXCEPTION(Serialization, except::IOException) + +/*! + * \class ParseException + * \brief Throwable related to failing to parse data. + */ +DECLARE_EXTENDED_EXCEPTION(Parse, except::IOException) + +} + +#endif + diff --git a/modules/c++/except/include/except/HandlerInterface.h b/modules/c++/except/include/except/HandlerInterface.h new file mode 100644 index 000000000..3cd4a66bf --- /dev/null +++ b/modules/c++/except/include/except/HandlerInterface.h @@ -0,0 +1,106 @@ +/* ========================================================================= + * This file is part of except-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * except-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __HANDLER_INTERFACE_H__ +#define __HANDLER_INTERFACE_H__ + +#include "except/Context.h" +#include "except/Error.h" +#include "except/Exception.h" + +/*! + * \file HandlerInterface.h + * \brief This is a class to handle a message in some time and place + * It takes a Context for every function, which is usually provided via + * macros, and an Exception, Error, status message or warning message. + * Here, we simply provide the abstract interface + * + * + */ +namespace except +{ +/*! + * \class HandlerInterface + * \brief A class for handling notification events + * While this class used to service only Throwable events, it was + * extended to provide a status message and a warning message. + * These events propogate to the HandlerInterface, usual via macro, + * and any derivation of this interface will define how to handle + * this notification event. The default implementation, used by + * ExceptionFactory if nothing is provided simply throws the error + * or exception. + */ +class HandlerInterface +{ +public: + //! Constructor + HandlerInterface() + {} + //! Destructor + virtual ~HandlerInterface() + {} + + /*! + * Given an error, and a context in which it was produced, handle + * the event + * \param c The context in which the error was produced + * \param e The error which was generated + */ + virtual void onRaise(Context c, const Error& e) = 0; + + /*! + * Given an exception, and a context in which it was produced, handle + * the event + * \param c The context in which the exception was produced + * \param e The exception which was generated + */ + virtual void onRaise(Context c, const Exception& e) = 0; + + /*! + * Given an status, and a context in which it was produced, handle + * the event. + * \param c The context in which the status was produced + * \param status The status which was generated + */ + virtual void onStatus(Context c, const std::string& status) = 0; + + /*! + * Given an warning, and a context in which it was produced, handle + * the event. + * \param c The context in which the warning was produced + * \param warning The warning which was generated + */ + virtual void onWarning(Context c, const std::string& warning) = 0; + + /*! + * Given a debug statement, and a context in which it was produced, + * handle the event. + * \param c The context in which the debug statement was produced + * \param dbg The debug statement that was generated + */ + virtual void onDebug(Context c, const std::string& dbg) = 0; + +}; +} + + +#endif diff --git a/modules/c++/except/include/except/Throwable.h b/modules/c++/except/include/except/Throwable.h new file mode 100644 index 000000000..74ac2ac8a --- /dev/null +++ b/modules/c++/except/include/except/Throwable.h @@ -0,0 +1,142 @@ +/* ========================================================================= + * This file is part of except-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * except-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __EXCEPT_THROWABLE_H__ +#define __EXCEPT_THROWABLE_H__ + +#include +#include +#include "except/Trace.h" + +/*! + * \file Throwable.h + * \brief Contains the classes to do with error handling + * + * A Throwable has two possible classifications (according to java, and for our + * purposes, that is good enough): Errors and Exceptions. + */ +namespace except +{ + +/*! + * \class Throwable + * \brief The interface for exceptions and errors + * + * This class provides the base interface for exceptions and errors. + */ +class Throwable +{ +public: + + /*! + * Default Constructor + */ + Throwable() : + mMessage("") + { + } + + /*! + * Constructor. Takes a message + * \param message The message + */ + Throwable(const std::string& message) : + mMessage(message) + { + } + + /*! + * Constructor. Takes a Context. + * \param c The Context + */ + Throwable(Context c); + + /*! + * Constructor. Takes a Throwable and a Context + * \param t The throwable + * \param c The Context + */ + Throwable(const Throwable& t, Context c); + + /*! + * Destructor + */ + virtual ~Throwable() + { + } + + /*! + * Get the message + * \return The message + */ + std::string getMessage() const + { + return mMessage; + } + + /*! + * Get the trace + * \return The trace (const) + */ + const Trace& getTrace() const + { + return mTrace; + } + + /*! + * Get the trace + * \return The trace (non-const) + */ + Trace& getTrace() + { + return mTrace; + } + + /*! + * Get the type id + * \return The type + */ + virtual std::string getType() const + { + return "Throwable"; + } + + virtual std::string toString() const + { + std::ostringstream s; + s << getType() << ": " << getMessage(); + + const Trace& t = getTrace(); + if (t.getSize() > 0) + s << ": " << t; + return s.str(); + } + +protected: + //! The name of exception trace + Trace mTrace; + //! The name of the message the exception was thrown + std::string mMessage; +}; +} + +#endif diff --git a/modules/c++/except/include/except/Trace.h b/modules/c++/except/include/except/Trace.h new file mode 100644 index 000000000..bd578c130 --- /dev/null +++ b/modules/c++/except/include/except/Trace.h @@ -0,0 +1,112 @@ +/* ========================================================================= + * This file is part of except-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * except-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __EXCEPT_TRACE_H__ +#define __EXCEPT_TRACE_H__ + +#include +#include +#include "except/Context.h" + +/*! + * \file Trace.h + * \brief Class for holding exception traces + * + */ + +namespace except +{ +/*! + * \class Trace + * \brief Holds stack of context information + */ +class Trace +{ +public: + /*! + * Default Constructor + */ + Trace() + { + } + + /*! + * Gets size of stack + * \return the size + */ + size_t getSize() const + { + return mStack.size(); + } + + /*! + * Pushes Context onto the stack + * \param c The Context + */ + void pushContext(const Context& c) + { + mStack.push_front(c); + } + + /*! + * Pops Context off the stack + */ + void popContext() + { + mStack.pop_front(); + } + + /*! + * Gets first Context on stack + */ + const Context& getContext() const + { + return mStack.front(); + } + + /*! + * Get the stack + * \return The stack (const) + */ + const std::list& getStack() const + { + return mStack; + } + + /*! + * Get the stack + * \return The stack (non-const) + */ + std::list& getStack() + { + return mStack; + } + +private: + //! The name of the internal stack wrapped by the Trace + std::list mStack; +}; +} + +std::ostream& operator<<(std::ostream& os, const except::Trace& t); + +#endif diff --git a/modules/c++/except/include/import/except.h b/modules/c++/except/include/import/except.h new file mode 100644 index 000000000..f102d24c3 --- /dev/null +++ b/modules/c++/except/include/import/except.h @@ -0,0 +1,74 @@ +/* ========================================================================= + * This file is part of except-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * except-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __IMPORT_EXCEPT_H__ +#define __IMPORT_EXCEPT_H__ + +/*! + * \file except.h + * \brief The except module is a base library for exceptions + * + * Exceptions are fundamental to most modern C++ applications. + * The exception library contained herein uses the Java approach + * to defining exceptions. The base class is Throwable, which defines + * the class of all such events worthy of unwinding the stack, and being + * caught in try/catch blocks. Quite literally, a Throwable is something + * which, when produced, will be thrown. + * + * Like in java, there are two sub-categories of Throwable: + * Exception classes, and Error classes. Exceptions are considered to + * be types of Throwables that can be corrected once the state has been + * rolled back. They, in other words, are essentially non-fatal errors. + * Errors are typically things that the developer would consider serious + * (constituting behavior worthy of death). + * + * Generally speaking, when we use exceptions in this library, + * we throw our exception and we allow it to be caught by a surrounding + * try block. Thrown exceptions unwind the stack until they are caught + * by what is known as a catch block (Each try block must be coupled + * with a catch block. To catch, you simply need to give a parameter + * to the catch block. A parameter should always be caught by reference, + * otherwise it will take on attributes only of the class that it is + * caught (the benefits of inheritance are lost then). + * + * More specifically, in this library, we create an exception, usually + * taking a string or char* as the right-hand-side. Typically, a higher + * level "handler" will construct this message for us (it may be a + * combination of developer and handler -- similar to perror). We + * enforce, however, no such requirements in this package. + * + * + * + */ + +#include "except/Context.h" +#include "except/Trace.h" +#include "except/Throwable.h" +#include "except/Error.h" +#include "except/Exception.h" +#define EXCEPT_MAJOR_VERSION 0 +#define EXCEPT_MINOR_VERSION 1 +#define EXCEPT_MICRO_VERSION 0 + + +#endif diff --git a/modules/c++/except/source/Context.cpp b/modules/c++/except/source/Context.cpp new file mode 100644 index 000000000..7dff5504b --- /dev/null +++ b/modules/c++/except/source/Context.cpp @@ -0,0 +1,64 @@ +/* ========================================================================= + * This file is part of except-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * except-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#include +#include "except/Context.h" + +/*! + * \file Context.cpp + * \brief defines a class that contains the information surrounding an + * exception or error. + */ + +except::Context::Context(const except::Context& c) +{ + mMessage = c.getMessage(); + mTime = c.getTime(); + mFunc = c.getFunction(); + mFile = c.getFile(); + mLine = c.getLine(); +} + +except::Context& except::Context::operator=(const except::Context& c) +{ + if (&c != this) + { + mMessage = c.getMessage(); + mTime = c.getTime(); + mFunc = c.getFunction(); + mFile = c.getFile(); + mLine = c.getLine(); + } + return *this; +} + +std::ostream& operator<< (std::ostream& os, const except::Context& c) +{ + os << "(" << c.getFile() << ", "; + os << c.getLine() << ", "; + os << c.getFunction() << "): ["; + os << c.getTime() << "] '"; + os << c.getMessage() << "' "; + return os; +} + diff --git a/modules/c++/except/source/Throwable.cpp b/modules/c++/except/source/Throwable.cpp new file mode 100644 index 000000000..fad44b886 --- /dev/null +++ b/modules/c++/except/source/Throwable.cpp @@ -0,0 +1,42 @@ +/* ========================================================================= + * This file is part of except-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * except-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include "except/Throwable.h" + +except::Throwable::Throwable(except::Context c) +{ + // Assign c's message to our internal one + mMessage = c.getMessage(); + + // Push context onto exception stack + mTrace.pushContext(c); +} + +except::Throwable::Throwable(const except::Throwable& t, except::Context c) +{ + // Copy t's exception stack and push c onto local one + mTrace = t.getTrace(); + mTrace.pushContext(c); + + // Assign c's message as our internal one + mMessage = c.getMessage(); +} diff --git a/modules/c++/except/source/Trace.cpp b/modules/c++/except/source/Trace.cpp new file mode 100644 index 000000000..922a17ec1 --- /dev/null +++ b/modules/c++/except/source/Trace.cpp @@ -0,0 +1,35 @@ +/* ========================================================================= + * This file is part of except-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * except-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include + +std::ostream& operator<<(std::ostream& os, const except::Trace& t) +{ + const std::list& stack = t.getStack(); + + for (std::list::const_iterator it = stack.begin(); + it != stack.end(); ++it) + { + os << *it << std::endl; + } + return os; +} diff --git a/modules/c++/except/tests/Gen2Test.cpp b/modules/c++/except/tests/Gen2Test.cpp new file mode 100644 index 000000000..c6143553a --- /dev/null +++ b/modules/c++/except/tests/Gen2Test.cpp @@ -0,0 +1,83 @@ +/* ========================================================================= + * This file is part of except-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * except-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#include +#include "import/except.h" + +#define Ctxt(MESSAGE) Context(__FILE__, __LINE__, "Func", "Time", MESSAGE) + +using std::endl; using std::cout; +using namespace except; + +DECLARE_EXCEPTION(DivideByZero) +typedef DivideByZeroException DivideByZero; + +double Divide(double x, double y); + + +double callDivide(double x, double y) +{ + double z; + try + { + z = Divide(x, y); + } + catch (Throwable& t) + { + throw DivideByZero(t, Ctxt("Hello")); + } + return z; +} + +double Divide(double x, double y) +{ + if (y == 0) + { + throw DivideByZero(Ctxt("Hello again")); + } + return x / y; +} + +int main(int argc, char* argv[]) +{ + if (argc != 3) + { + cout << "Usage: " << argv[0] << " " << endl; + exit(1); + } + + double x = atof(argv[1]); + double y = atof(argv[2]); + + try + { + cout << "Dividing " << x << " and " << y << endl; + cout << "Answer is: " << callDivide(x, y) << endl; + } + catch (Throwable& t) + { + cout << "Why did you do that?" << endl; + cout << t.toString() << endl; + } + return 0; +} diff --git a/modules/c++/except/wscript b/modules/c++/except/wscript new file mode 100644 index 000000000..5da1951ed --- /dev/null +++ b/modules/c++/except/wscript @@ -0,0 +1,9 @@ +NAME = 'except' +MAINTAINER = 'jmrandol@users.sourceforge.net' +VERSION = '1.0' +UNITTEST_DEPS = 'sys' + +options = configure = distclean = lambda p: None + +def build(bld): + bld.module(**globals()) diff --git a/modules/c++/include/TestCase.h b/modules/c++/include/TestCase.h new file mode 100644 index 000000000..e3bb6d1aa --- /dev/null +++ b/modules/c++/include/TestCase.h @@ -0,0 +1,98 @@ +/* ========================================================================= + * This file is part of CODA-OSS + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * CODA-OSS is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __TEST_CASE_H__ +#define __TEST_CASE_H__ + +#ifdef __cplusplus + +# include +# include +# include +# include + +# define TEST_CHECK(X) try{ X(std::string(#X)); std::cerr << #X << ": PASSED" << std::endl; } catch(except::Throwable& ex) { die_printf("%s: FAILED: Exception thrown: %s\n", std::string(#X).c_str(), ex.toString().c_str()); } +# define TEST_ASSERT(X) if (!(X)) { die_printf("%s (%s,%s,%d): FAILED: Value should not be NULL\n", testName.c_str(), __FILE__, SYS_FUNC, __LINE__); } +# define TEST_ASSERT_NULL(X) if ((X) != NULL) { die_printf("%s (%s,%s,%d): FAILED: Value should be NULL\n", testName.c_str(), __FILE__, SYS_FUNC, __LINE__); } +# define TEST_ASSERT_FALSE(X) if ((X)) { die_printf("%s (%s,%s,%d): FAILED: Value should evaluate to false\n", testName.c_str(), __FILE__, SYS_FUNC, __LINE__); } +# define TEST_ASSERT_TRUE(X) if (!(X)) { die_printf("%s (%s,%s,%d): FAILED: Value should evaluate to true\n", testName.c_str(), __FILE__, SYS_FUNC, __LINE__); } +# define TEST_ASSERT_EQ(X1, X2) if ((X1) != (X2)) { die_printf("%s (%s,%s,%d): FAILED: Recv'd %s, Expected %s\n", testName.c_str(), __FILE__, SYS_FUNC, __LINE__, str::toString(X1).c_str(), str::toString(X2).c_str()); } +# define TEST_ASSERT_EQ_MSG(msg, X1, X2) if ((X1) != (X2)) die_printf("%s (%s,%d): FAILED (%s): Recv'd %s, Expected %s\n", testName.c_str(), __FILE__, __LINE__, (msg).c_str(), str::toString((X1)).c_str(), str::toString((X2)).c_str()); +# define TEST_ASSERT_NOT_EQ(X1, X2) if ((X1) == (X2)) { die_printf("%s (%s,%s,%d): FAILED: Recv'd %s should not equal %s\n", testName.c_str(), __FILE__, SYS_FUNC, __LINE__, str::toString(X1).c_str(), str::toString(X2).c_str()); } +# define TEST_ASSERT_NOT_EQ_MSG(msg, X1, X2) if ((X1) == (X2)) die_printf("%s (%s,%d): FAILED (%s): Recv'd %s should not equal %s\n", testName.c_str(), __FILE__, __LINE__, (msg).c_str(), str::toString((X1)).c_str(), str::toString((X2)).c_str()); +# define TEST_ASSERT_ALMOST_EQ_EPS(X1, X2, EPS) if (std::abs((X1) - (X2)) > EPS) die_printf("%s (%s,%d): FAILED: Recv'd %s, Expected %s\n", testName.c_str(), __FILE__, __LINE__, str::toString((X1)).c_str(), str::toString((X2)).c_str()); +# define TEST_ASSERT_ALMOST_EQ(X1, X2) if (std::abs((X1) - (X2)) > std::numeric_limits::epsilon()) { die_printf("%s (%s,%s,%d): FAILED: Recv'd %s, Expected %s\n", testName.c_str(), __FILE__, SYS_FUNC, __LINE__, str::toString(X1).c_str(), str::toString(X2).c_str()); } +# define TEST_ASSERT_GREATER_EQ(X1, X2) if ((X1) < X2) { die_printf("%s (%s,%s,%d): FAILED: Value should be greater than or equal\n", testName.c_str(), __FILE__, SYS_FUNC, __LINE__); } +# define TEST_ASSERT_GREATER(X1, X2) if ((X1) <= X2) { die_printf("%s (%s,%s,%d): FAILED: Value should be greater than\n", testName.c_str(), __FILE__, SYS_FUNC, __LINE__); } +# define TEST_ASSERT_LESSER_EQ(X1, X2) if ((X1) > X2) { die_printf("%s (%s,%s,%d): FAILED: Value should be less than or equal\n", testName.c_str(), __FILE__, SYS_FUNC, __LINE__); } +# define TEST_ASSERT_LESSER(X1, X2) if ((X1) >= X2) { die_printf("%s (%s,%s,%d): FAILED: Value should be less than\n", testName.c_str(), __FILE__, SYS_FUNC, __LINE__); } +# define TEST_FAIL(msg) die_printf("%s (%s,%s,%d): FAILED: %s\n", testName.c_str(), __FILE__, SYS_FUNC, __LINE__, str::toString(msg).c_str()); +# define TEST_EXCEPTION(X) try{ (X); die_printf("%s (%s,%s,%d): FAILED: Should have thrown exception\n", testName.c_str(), __FILE__, SYS_FUNC, __LINE__); } catch (except::Throwable&){} +# define TEST_CASE(X) void X(std::string testName) + +#else /* C only */ +# include +# include +# include +# include + +/* Copied from sys/Conf.h */ +# define TEST_FILE __FILE__ +# define TEST_LINE __LINE__ +# if defined(__GNUC__) +# define TEST_FUNC __PRETTY_FUNCTION__ +# elif __STDC_VERSION__ < 199901 +# define TEST_FUNC "unknown function" +# else /* Should be c99 */ +# define TEST_FUNC __func__ +# endif + +# define TEST_CHECK(X) X(#X); fprintf(stderr, "%s : PASSED\n", #X); +# define TEST_CHECK_ARGS(X) X(#X,argc,argv); fprintf(stderr, "%s : PASSED\n", #X); +# define TEST_ASSERT(X) if (!(X)) { \ + fprintf(stderr, "%s (%s,%s,%d) : FAILED: Value should not be NULL\n", testName, TEST_FILE, TEST_FUNC, TEST_LINE); \ + exit(EXIT_FAILURE); \ +} +# define TEST_ASSERT_NULL(X) if ((X) != NULL) { \ + fprintf(stderr, "%s (%s,%s,%d) : FAILED: Value should be NULL\n", testName, TEST_FILE, TEST_FUNC, TEST_LINE); \ + exit(EXIT_FAILURE); \ +} +# define TEST_ASSERT_EQ_STR(X1, X2) if (strcmp((X1), (X2)) != 0) { \ + fprintf(stderr, "%s (%s,%s,%d) : FAILED: Recv'd %s, Expected %s\n", testName, TEST_FILE, TEST_FUNC, TEST_LINE, X1, X2); \ + exit(EXIT_FAILURE); \ +} +# define TEST_ASSERT_EQ_INT(X1, X2) if ((X1) != (X2)) { \ + fprintf(stderr, "%s (%s,%s,%d) : FAILED: Recv'd %d, Expected %d\n", testName, TEST_FILE, TEST_FUNC, TEST_LINE, (int)X1, (int)X2); \ + exit(EXIT_FAILURE); \ +} +/* TODO use epsilon for comparing floating points */ +# define TEST_ASSERT_EQ_FLOAT(X1, X2) if (fabs((X1) - (X2)) > .0000001f) { \ + fprintf(stderr, "%s (%s,%s,%d) : FAILED: Recv'd %f, Expected %f\n", testName, TEST_FILE, TEST_FUNC, TEST_LINE, X1, X2); \ + exit(EXIT_FAILURE); \ +} + +# define TEST_CASE(X) void X(const char* testName) +# define TEST_CASE_ARGS(X) void X(const char* testName, int argc, char **argv) + +#endif + +#endif diff --git a/modules/c++/io/include/import/io.h b/modules/c++/io/include/import/io.h new file mode 100644 index 000000000..057af4e14 --- /dev/null +++ b/modules/c++/io/include/import/io.h @@ -0,0 +1,78 @@ +/* ========================================================================= + * This file is part of io-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * io-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __IMPORT_IO_H__ +#define __IMPORT_IO_H__ + +/*! + * \file io.h + * \brief Includes all headers necessary for IO. + * + * This package is based on the Java io package. + * For the upcoming 0.1.1 release of the modules, + * we will support the io.File API as well. + * + * The io package takes a more simple but still powerful + * approach to streaming. We have a built in buffering mechanism + * that can be activated simply by using the InputStream interface's + * streamTo() method, connecting it to an OutputStream. + * + * Many of the streams are also implemented as filters, allowing them + * to pipe or stream, or sort data that is incoming, and affect its + * appearance as it is outgoing. + * + * Furthermore, BidirectionalStream implementors share the duties of + * InputStream and OutputStream, allowing for a 2-way abstraction that + * Java is lacking, while supporting a whole slew of InputStream sources + * that C++ does not support at all (URLs, sockets, serializers, etc). + * + * Finally, we support the beginnings of serialization at this level, + * although we do little to enforce standards for it (we recommend XML/SOAP + * for most applications. Check out the SOAPMessage class in xml.soap. + * + */ + +#include "io/BidirectionalStream.h" +#include "io/ByteStream.h" +#include "io/DataStream.h" +#include "io/DbgStream.h" +#include "io/InputStream.h" +#include "io/OutputStream.h" +#include "io/FileInputStream.h" +#include "io/FileOutputStream.h" +#include "io/Seekable.h" +#include "io/Serializable.h" +#include "io/SerializableFile.h" +#include "io/PipeStream.h" +#include "io/StandardStreams.h" +#include "io/StringStream.h" +#include "io/NullStreams.h" +#include "io/ProxyStreams.h" +#include "io/FileUtils.h" +#include "io/SerializableArray.h" +#include "io/CountingStreams.h" +#include "io/RotatingFileOutputStream.h" + +//#include "io/MMapInputStream.h" +//using namespace io; + +#endif diff --git a/modules/c++/io/include/io/BidirectionalStream.h b/modules/c++/io/include/io/BidirectionalStream.h new file mode 100644 index 000000000..00e2679a6 --- /dev/null +++ b/modules/c++/io/include/io/BidirectionalStream.h @@ -0,0 +1,46 @@ +/* ========================================================================= + * This file is part of io-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * io-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __IO_BIDIRECTIONAL_STREAM_H__ +#define __IO_BIDIRECTIONAL_STREAM_H__ + +#include "io/InputStream.h" +#include "io/OutputStream.h" + +/*! + * \file + * \brief Provides an interface for a stream that is both input + * and output. + */ + +namespace io +{ +/*! + * \class BidirectionalStream + * \brief Provides a input/output stream as one class. + */ +struct BidirectionalStream: public InputStream, public OutputStream +{ +}; + +} +#endif diff --git a/modules/c++/io/include/io/ByteStream.h b/modules/c++/io/include/io/ByteStream.h new file mode 100644 index 000000000..8285ba3b6 --- /dev/null +++ b/modules/c++/io/include/io/ByteStream.h @@ -0,0 +1,153 @@ +/* ========================================================================= + * This file is part of io-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * io-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __IO_BYTE_STREAM_H__ +#define __IO_BYTE_STREAM_H__ + +#include +#include "io/BidirectionalStream.h" +#include "sys/Conf.h" +#include "except/Error.h" +#include "except/Exception.h" +#include "io/SeekableStreams.h" + +/*! + * \file + * \brief Class for buffering data, inherits from BidirectionalStream. + * + * This type exists to handle piped data. If all of your + * data is ascii, it is easy just to use a std::string from + * C++ to handle this. However, for binary transfers, arbitrary + * 0's can be anywhere (Null-bytes) making it impossible to use + * strings as containers. + * + * Alternatively, we could have used std::stream, + * but having it in a container makes it all less accessible, so we + * opted for our own growable data array + */ +namespace io +{ +/*! + * \class ByteStream + * \brief Class for buffering data, inherits from BidirectionalStream. + * + * This type exists to handle piped data. If all of your + * data is ascii, it is easy just to use a std::string from + * C++ to handle this. However, for binary transfers, arbitrary + * 0's can be anywhere (Null-bytes) making it impossible to use + * strings as containers. + */ +class ByteStream: public SeekableBidirectionalStream +{ +public: + + //! Default constructor + ByteStream() : + mData(std::stringstream::in | std::stringstream::out + | std::stringstream::binary) + { + } + + //! Destructor + ~ByteStream() + { + } + + /*! + * Returns the stringstream associated with this ByteStream + * \return the stringstream + */ + const std::stringstream& stream() const + { + return mData; + } + + sys::Off_T tell() + { + return mData.tellg(); + } + + sys::Off_T seek(sys::Off_T offset, Whence whence) + { + std::ios::seekdir flags; + switch (whence) + { + case START: + flags = std::ios::beg; + break; + + case END: + flags = std::ios::end; + break; + + default: + flags = std::ios::cur; + + } + + // off_t orig = tell(); + mData.seekg(offset, flags); + return tell(); + } + + /*! + * Returns the available bytes to read from the stream + * \return the available bytes to read + */ + sys::Off_T available(); + + using OutputStream::write; + + /*! + * Writes the bytes in data to the stream. + * \param b the data to write to the stream + * \param size the number of bytes to write to the stream + */ + void write(const sys::byte *b, sys::Size_T size); + + /*! + * Read up to len bytes of data from this buffer into an array + * update the mark + * \param b Buffer to read into + * \param len The length to read + * \throw IoException + * \return The number of bytes read + */ + virtual sys::SSize_T read(sys::byte *b, sys::Size_T len); + + //! Returns the internal std::stringstream + std::stringstream& stream() + { + return mData; + } + + void reset() + { + mData.str(""); + } + +protected: + std::stringstream mData; +}; +} + +#endif diff --git a/modules/c++/io/include/io/CountingStreams.h b/modules/c++/io/include/io/CountingStreams.h new file mode 100644 index 000000000..b73d6199e --- /dev/null +++ b/modules/c++/io/include/io/CountingStreams.h @@ -0,0 +1,69 @@ +/* ========================================================================= + * This file is part of io-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * io-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __IO_COUNTING_STREAMS_H__ +#define __IO_COUNTING_STREAMS_H__ + +#include "io/ProxyStreams.h" + +namespace io +{ + +/** + * An OutputStream that keeps track of the number of bytes written to the stream. + */ +class CountingOutputStream: public ProxyOutputStream +{ +public: + CountingOutputStream(OutputStream *proxy, bool ownPtr = false) : + ProxyOutputStream(proxy, ownPtr), mByteCount(0) + { + } + virtual ~CountingOutputStream() + { + } + + using ProxyOutputStream::write; + + virtual void write(const sys::byte* b, sys::Size_T len) + { + ProxyOutputStream::write(b, len); + mByteCount += len; + } + + sys::Off_T getCount() const + { + return mByteCount; + } + + void resetCount() + { + mByteCount = 0; + } + +protected: + sys::Off_T mByteCount; +}; + +} + +#endif diff --git a/modules/c++/io/include/io/DataStream.h b/modules/c++/io/include/io/DataStream.h new file mode 100644 index 000000000..4f1f618c8 --- /dev/null +++ b/modules/c++/io/include/io/DataStream.h @@ -0,0 +1,115 @@ +/* ========================================================================= + * This file is part of io-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * io-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __DATA_STREAM_H__ +#define __DATA_STREAM_H__ + +#include "io/Serializable.h" + +/*! + * \file DataStream.h + * \brief Wrap a ByteStream with a Serializable interface. + * + * This class is actually hiding an internal ByteStream, but it + * is also considered to be Serializable, meaning that it conforms to + * the interface for a SerializableConnection + */ +namespace io +{ +/*! + * \class DataStream + * \brief Wraps a ByteStream with a Serializable interface. + * + * This class is actually hiding an internal ByteStream, but it + * is also considered to be Serializable, meaning that it conforms to + * the interface for a SerializableConnection + */ +class DataStream: public io::Serializable +{ +public: + //! Default constructor + DataStream() + { + } + //! Deconstructor + virtual ~DataStream() + { + } + + //! Returns the number of bytes available to read. + virtual sys::Off_T available() + { + return mByteStream.available(); + } + + /*! + * Read bytes from our byte stream into the buffer + * \param data The data buffer to read to + * \param size The size of the data buffer to read + */ + virtual sys::SSize_T read(sys::byte* data, sys::Size_T size) + { + return mByteStream.read(data, size); + } + + /*! + * Write bytes from into our byte stream from the buffer + * \param data The data buffer to read from + * \param size The size of the data buffer. + */ + virtual void write(const sys::byte* data, sys::Size_T size) + { + mByteStream.write(data, size); + } + + /*! + * Outputs this object into an output stream. + * \param os the OutputStream to write to + */ + virtual void serialize(io::OutputStream& os) + { + mByteStream.streamTo(os); + } + + /*! + * Unpack this input stream to the object + * \param is Stream to read object from + */ + virtual void deserialize(io::InputStream& is) + { + is.streamTo(mByteStream); + } + + io::ByteStream& getStream() + { + return mByteStream; + } + const io::ByteStream& getStream() const + { + return mByteStream; + } +protected: + io::ByteStream mByteStream; +}; +} + +#endif diff --git a/modules/c++/io/include/io/DbgStream.h b/modules/c++/io/include/io/DbgStream.h new file mode 100644 index 000000000..a75201e6e --- /dev/null +++ b/modules/c++/io/include/io/DbgStream.h @@ -0,0 +1,124 @@ +/* ========================================================================= + * This file is part of io-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * io-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __DBG_STREAM_H__ +#define __DBG_STREAM_H__ + +#include "io/OutputStream.h" +#include + + +/*! + * \file DbgStream.h + * \brief This is the class for debugging with streams + * + * This class should be used by high-level entities for defining + * degug streams. If the stream is "on", printing will occur to a bound + * OutputStream (Impl style). Otherwise, nothing will occur + * + */ + +namespace io +{ +/*! + * \class DbgStream + * \brief A class for printing to a debug stream + * + * This class should be used by high-level entities for defining + * degug streams. If the stream is "on", printing will occur to a bound + * OutputStream (Impl style). Otherwise, nothing will occur + * + */ + +class DbgStream : public OutputStream +{ +public: + //! Constructor + DbgStream() : mOn(false) + {} + + /*! + * Alternate constructor + * \param s An output stream to adopt + * \param on The state of the stream (on or off) + */ + DbgStream(OutputStream* s, bool on = false) + { + set(s, false); + } + + using OutputStream::write; + + /*! + * Set the output and debug stream + * \param s An output stream to adopt + * \param on The state of the stream (on or off) + */ + virtual void set(OutputStream* s, bool on = false) + { + mOn = on; + mStream.reset(s); + } + //! Destructor + virtual ~DbgStream() + {} + + /*! + * This method uses the bound OutputStream to print, + * if the switch is on. + * \param b The byte array to write to the stream + * \param len The length + * \throw IOException + */ + virtual void write(const sys::byte* b, sys::Size_T len) + { + if (mOn) + { + mStream->write(b, len); + } + } + + /*! + * Is the stream on or off?? + * \return The state of the stream + */ + bool isOn() + { + return mOn; + } + + /*! + * Set the state of the stream + * \param on The new state of the stream + */ + void setDebug(bool on) + { + mOn = on; + } +protected: + //! The bound stream + std::auto_ptr mStream; + //! On or off?? + bool mOn; +}; +} +#endif diff --git a/modules/c++/io/include/io/FileInputStream.h b/modules/c++/io/include/io/FileInputStream.h new file mode 100644 index 000000000..4d46f8db5 --- /dev/null +++ b/modules/c++/io/include/io/FileInputStream.h @@ -0,0 +1,39 @@ +/* ========================================================================= + * This file is part of io-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * io-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __IO_FILE_INPUT_STREAM_H__ +#define __IO_FILE_INPUT_STREAM_H__ + +#if defined(USE_IO_STREAMS) +# include "io/FileInputStreamIOS.h" +namespace io { + typedef FileInputStreamIOS FileInputStream; +} +#else +# include "io/FileInputStreamOS.h" +namespace io { + typedef FileInputStreamOS FileInputStream; +} +#endif + + +#endif diff --git a/modules/c++/io/include/io/FileInputStreamIOS.h b/modules/c++/io/include/io/FileInputStreamIOS.h new file mode 100644 index 000000000..03329f9b9 --- /dev/null +++ b/modules/c++/io/include/io/FileInputStreamIOS.h @@ -0,0 +1,152 @@ +/* ========================================================================= + * This file is part of io-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * io-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __IO_FILE_INPUT_STREAM_IOS_H__ +#define __IO_FILE_INPUT_STREAM_IOS_H__ + +#if defined(USE_IO_STREAMS) + +#include +#include +#include +#include "except/Exception.h" +#include "io/InputStream.h" +#include "io/SeekableStreams.h" + +/*! + * \file FileInputStreamIOS.h + * \brief The InputStream representation of a file + * \todo Redefine the readln function to use getline() + * The file contains the representation of an input stream + * from a file. It mimics the Java io package API, with added + * streaming capabilities + */ + +namespace io +{ + +/*! + * \class FileInputStreamIOS + * \brief An InputStream from file + * + * Use this object to create an input stream, where the available() + * method is based on the pos in the file, and the streamTo() and read() + * are file operations + */ +class FileInputStreamIOS : public SeekableInputStream +{ +public: + //! Constructor + FileInputStreamIOS() + {} + + /*! + * Alternate Constructor. Takes an input file and a mode + * \param inputFile The file name + * \param mode The mode to open the file in + */ + FileInputStreamIOS(const std::string& inputFile, + std::ios::openmode mode = std::ios::in); + + + /*! + * Alternate Constructor. Takes an input file and a mode + * \param inputFile The file name + * \param mode The mode to open the file in + */ + FileInputStreamIOS(const char* inputFile, + std::ios::openmode mode = std::ios::in); + + + virtual ~FileInputStreamIOS() + { + if (isOpen() ) close(); + } + /*! + * Returns the number of bytes that can be read + * without blocking by the next caller of a method for this input + * + * \throw except::IOException + * \return number of bytes which are readable + * + */ + virtual sys::Off_T available(); + + /*! + * Report whether or not the file is open + * \return True if file is open + */ + virtual bool isOpen(); + + + /*! + * Open the file in the mode provided + * \param file The file to open + * \param mode The mode + */ + virtual void open(const char *file, + std::ios::openmode mode = std::ios::in ); + + + /*! + * Go to the offset at the location specified. + * \return The number of bytes between off and our origin. + */ + virtual sys::Off_T seek(sys::Off_T offset, Whence whence); + + /*! + * Tell the current offset + * \return The byte offset + */ + virtual sys::Off_T tell(); + + //! Close the file + void close(); + //using InputStream::read; + /*! + * Read up to len bytes of data from input stream into an array + * + * \param b Buffer to read into + * \param len The length to read + * \throw except::IOException + * \return The number of bytes read + * + */ + virtual sys::SSize_T read(sys::byte* b, sys::Size_T len); + + /*! + * Access the stream directly + * \return The stream in native C++ + */ + virtual std::ifstream& stream() + { + return mFStream; + } +protected: + std::ifstream mFStream; +}; + + + +} +#endif +#endif diff --git a/modules/c++/io/include/io/FileInputStreamOS.h b/modules/c++/io/include/io/FileInputStreamOS.h new file mode 100644 index 000000000..44d52b43c --- /dev/null +++ b/modules/c++/io/include/io/FileInputStreamOS.h @@ -0,0 +1,174 @@ +/* ========================================================================= + * This file is part of io-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * io-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __IO_FILE_INPUT_STREAM_OS_H__ +#define __IO_FILE_INPUT_STREAM_OS_H__ + +#if !defined(USE_IO_STREAMS) + +#include "except/Exception.h" +#include "sys/File.h" +#include "io/InputStream.h" +#include "io/SeekableStreams.h" + + +/*! + * \file FileInputStreamOS.h + * \brief The InputStream representation of a file using the OS handle + * The file contains the representation of an input stream + * from a file. It mimics the Java io package API, with added + * streaming capabilities + */ + +namespace io +{ + +/*! + * \class FileInputStreamOS + * \brief An InputStream from file + * + * Use this object to create an input stream, where the available() + * method is based on the pos in the file, and the streamTo() and read() + * are file operations + */ +class FileInputStreamOS : public SeekableInputStream +{ +protected: + sys::File mFile; +public: + + //! Constructor + FileInputStreamOS() + {} + + /*! + * Alternate Constructor. Takes an input file and a mode + * \param inputFile The file name + * \param mode The mode to open the file in + */ + FileInputStreamOS(const std::string& inputFile) + { + // Let this SystemException slide for now + mFile.create(inputFile, + sys::File::READ_ONLY, + sys::File::EXISTING); + } + + FileInputStreamOS(const sys::File& inputFile) + { + mFile = inputFile; + } + + virtual ~FileInputStreamOS() + {} + + /*! + * Returns the number of bytes that can be read + * without blocking by the next caller of a method for this input + * + * \throw except::IOException + * \return number of bytes which are readable + * + */ + virtual sys::Off_T available(); + + /*! + * Report whether or not the file is open + * \return True if file is open + */ + virtual bool isOpen() + { + return mFile.isOpen(); + } + + + /*! + * Open the file in the mode provided + * \param file The file to open + * \param mode The mode + */ + virtual void create(const std::string& str) + { + mFile.create(str, + sys::File::READ_ONLY, + sys::File::EXISTING); + + } + + + + /*! + * Go to the offset at the location specified. + * \return The number of bytes between off and our origin. + */ + virtual sys::Off_T seek(sys::Off_T off, Whence whence) + { + int from; + switch (whence) + { + case END: + from = sys::File::FROM_END; + break; + + case START: + from = sys::File::FROM_START; + break; + + default: + from = sys::File::FROM_CURRENT; + } + return mFile.seekTo( off, from ); + } + + /*! + * Tell the current offset + * \return The byte offset + */ + virtual sys::Off_T tell() + { + return mFile.getCurrentOffset(); + } + + //! Close the file + void close() + { + mFile.close(); + } + + /*! + * Read up to len bytes of data from input stream into an array + * + * \param b Buffer to read into + * \param len The length to read + * \throw except::IOException + * \return The number of bytes read + * + */ + virtual sys::SSize_T read(sys::byte* b, sys::Size_T len); + +}; + + + +} +#endif +#endif diff --git a/modules/c++/io/include/io/FileOutputStream.h b/modules/c++/io/include/io/FileOutputStream.h new file mode 100644 index 000000000..1b16aa723 --- /dev/null +++ b/modules/c++/io/include/io/FileOutputStream.h @@ -0,0 +1,38 @@ +/* ========================================================================= + * This file is part of io-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * io-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __IO_FILE_OUTPUT_STREAM_H__ +#define __IO_FILE_OUTPUT_STREAM_H__ + +#if defined(USE_IO_STREAMS) +# include "io/FileOutputStreamIOS.h" +namespace io { + typedef FileOutputStreamIOS FileOutputStream; +} +#else +# include "io/FileOutputStreamOS.h" +namespace io { + typedef FileOutputStreamOS FileOutputStream; +} +#endif + +#endif diff --git a/modules/c++/io/include/io/FileOutputStreamIOS.h b/modules/c++/io/include/io/FileOutputStreamIOS.h new file mode 100644 index 000000000..556357eba --- /dev/null +++ b/modules/c++/io/include/io/FileOutputStreamIOS.h @@ -0,0 +1,140 @@ +/* ========================================================================= + * This file is part of io-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * io-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __IO_FILE_OUTPUT_STREAM_IOS_H__ +#define __IO_FILE_OUTPUT_STREAM_IOS_H__ + +#if defined(USE_IO_STREAMS) +#include +#include +#include +#include "io/SeekableStreams.h" +#include +#include + + +/*! + * \file FileOutputStreamIOS.h + * \brief The OutputStream representation of a file + * + * The file contains the representation of an input stream + * from a file. It mimics the Java io package API. These classes are deprecated, + */ + +namespace io +{ + + +/*! + * \class FileOutputStreamOS + * \brief A type of OutputStream that writes to file + * + * This class corresponds closely to its java namesake. + * It also leverages upon the std::iostream package from C++, + * allowing its native type to be accessible to the developer, + * should he or she have the desire to modify it directly + */ +class FileOutputStreamIOS : public OutputStream + +{ +public: + //! Default constructor + FileOutputStreamIOS() + {} + + + /*! + * Alternate Constructor. Takes an output file and a mode + * \param outputFile The file name + * \param creationFlags see sys::File + */ + FileOutputStreamIOS(const std::string& outputFile, + int creationFlags = sys::File::CREATE | sys::File::TRUNCATE); + + /*! + * Alternate Constructor. Takes an output file and a mode + * \param outputFile The file name + * \param creationFlags see sys::File + */ + FileOutputStreamIOS(const char* outputFile, + int creationFlags = sys::File::CREATE | sys::File::TRUNCATE); + + //! Deconstructor, closes the file stream. + virtual ~FileOutputStreamIOS() + { + if (isOpen()) close(); + } + + /*! + * Report whether or not the file is open + * \return True if file is open + */ + virtual bool isOpen(); + + /*! + * Open the file in the mode provided + * \param file The file to open + * \param mode The mode + */ + virtual void open(const char *file, + std::ios::openmode mode = std::ios::out); + + using OutputStream::write; + + //! Close the file + void close(); + + /*! + * This method defines a given OutputStream. By defining, + * this method, you can define the unique attributes of an OutputStream + * inheriting class. + * \param b The byte array to write to the stream + * \param len the length of bytes to write + * \throw IoException + */ + virtual void write(const sys::byte* b, sys::Size_T len); + /*! + * Access the stream directly + * \return The stream in native C++ + */ + virtual std::ofstream& stream() + { + return mFStream; + } + + virtual void flush() + { + mFStream.flush(); + } + + sys::Off_T seek(sys::Off_T offset, io::Seekable::Whence whence); + + sys::Off_T tell(); + +protected: + std::ofstream mFStream; + std::string mFileName; +}; + +} +#endif +#endif diff --git a/modules/c++/io/include/io/FileOutputStreamOS.h b/modules/c++/io/include/io/FileOutputStreamOS.h new file mode 100644 index 000000000..3a527a7c5 --- /dev/null +++ b/modules/c++/io/include/io/FileOutputStreamOS.h @@ -0,0 +1,122 @@ +/* ========================================================================= + * This file is part of io-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * io-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __IO_FILE_OUTPUT_STREAM_OS_H__ +#define __IO_FILE_OUTPUT_STREAM_OS_H__ + +#if !defined(USE_IO_STREAMS) + +#include "io/SeekableStreams.h" +#include "sys/File.h" + + +/*! + * \file FileOutputStream.h + * \brief The OutputStream representation of a file + * + * The file contains the representation of an input stream + * from a file. It mimics the Java io package API. + */ + +namespace io +{ + +/*! + * \class FileOutputStreamOS + * \brief A type of OutputStream that writes to file using OS FDs + * + * This class corresponds closely to its java namesake. + * It uses native file handles to make writes. + */ +class FileOutputStreamOS : public SeekableOutputStream + +{ +protected: + sys::File mFile; +public: + //! Default constructor + FileOutputStreamOS() + {} + + + /*! + * Alternate Constructor. Takes an output file and a mode + * \param outputFile The file name + * \param creationFlags see sys::File + */ + FileOutputStreamOS(const std::string& outputFile, + int creationFlags = sys::File::CREATE | sys::File::TRUNCATE); + + + //! Destructor, closes the file stream. + virtual ~FileOutputStreamOS() + {} + + /*! + * Report whether or not the file is open + * \return True if file is open + */ + virtual bool isOpen() + { + return mFile.isOpen(); + } + + /*! + * Open the file in the mode provided + * \param file The file to open + * \param creationFlags see sys::File + */ + virtual void create(const std::string& str, + int creationFlags = sys::File::CREATE | sys::File::TRUNCATE); + + //! Close the file + void close() + { + mFile.close(); + } + + virtual void flush(); + + sys::Off_T seek(sys::Off_T offset, io::Seekable::Whence whence); + + sys::Off_T tell(); + + using OutputStream::write; + + /*! + * This method defines a given OutputStream. By defining, + * this method, you can define the unique attributes of an OutputStream + * inheriting class. + * \param b The byte array to write to the stream + * \param len the length of bytes to write + * \throw IoException + */ + virtual void write(const sys::byte* b, sys::Size_T len); + + + +}; +} + +#endif +#endif + diff --git a/modules/c++/io/include/io/FileUtils.h b/modules/c++/io/include/io/FileUtils.h new file mode 100644 index 000000000..f74b1b656 --- /dev/null +++ b/modules/c++/io/include/io/FileUtils.h @@ -0,0 +1,60 @@ +/* ========================================================================= + * This file is part of io-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * io-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __IO_FILE_UTILS_H__ +#define __IO_FILE_UTILS_H__ + +#include +#include +#include + +namespace io +{ + +/** + * Static file manipulation utilities. + */ +class FileUtils +{ +public: + /** + * Creates a file in the given directory. It will try to use the filename + * given. If overwrite is false, it will create a filename based on the + * given one. If the given filename is empty, a temporary name is used. + */ + static std::string createFile(std::string dirname, std::string filename = + std::string(""), bool overwrite = true) throw (except::IOException); + + static void touchFile(std::string filename) throw (except::IOException); + + static void forceMkdir(std::string dirname) throw (except::IOException); + +private: + //private constructor + FileUtils() + { + } +}; + +} + +#endif diff --git a/modules/c++/io/include/io/InputStream.h b/modules/c++/io/include/io/InputStream.h new file mode 100644 index 000000000..ec40b9753 --- /dev/null +++ b/modules/c++/io/include/io/InputStream.h @@ -0,0 +1,118 @@ +/* ========================================================================= + * This file is part of io-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * io-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __IO_INPUT_STREAM_H__ +#define __IO_INPUT_STREAM_H__ + +#include "sys/Dbg.h" +#include "io/OutputStream.h" + +/*! + * \file InputStream.h + * \brief Contains java-like InputStream object + * + * This file contains the details of the implemenation of + * a java-like InputStream interface. The interface has some + * simplifications and some extensions, simultaneously + */ + +namespace io +{ + +/*! + * \class InputStream + * \brief Class for handling input byte streams + * + * This class is somewhat akin to the corresponding java + * class. It is responsible for reading, and it is + * streamable. When the streaming feature is used, an internal + * buffer is used, and the destination is an OutputStream. + * This "piping" feature is not found in the java class, + * but it is important because it allows for quick, efficient transfers + * of large streams of bytes. + * + */ +class InputStream +{ +public: + enum + { + IS_EOF = -1, IS_END = -1, DEFAULT_CHUNK_SIZE = 1024 + }; + + //! Default Constructor + InputStream() + { + } + + //! Default Destructor + virtual ~InputStream() + { + } + + /*! + * Returns the number of bytes that can be read + * without blocking by the next caller of a method for this input. + * \throw IOException + * \return number of bytes which are readable + */ + virtual sys::Off_T available() + { + return 0; + } + + /*! + * Read up to len bytes of data from input stream into an array + * \param b Buffer to read into + * \param len The length to read + * \throw IOException + * \return The number of bytes read, or -1 if EOF + */ + virtual sys::SSize_T read(sys::byte* b, sys::Size_T len) = 0; + + /*! + * Read either a buffer of len size, or up until a newline, + * whichever comes first + * \param cStr String to read data into + * \param strLenPlusNullByte The max length we will read + */ + virtual sys::SSize_T readln(sys::byte *cStr, + const sys::Size_T strLenPlusNullByte); + + /*! + * The streaming occurs as follows: If the numBytes is IS_END, + * we want to pipe all bytes to the output handler + * Otherwise, we'll take what we've got + * We want to return the number of bytes total. + * \param soi Stream to write to + * \param numBytes The number of bytes to stream + * \throw BadPipeException + * \return The number of bytes transferred from the + * input stream to the output stream + */ + virtual sys::SSize_T streamTo(OutputStream& soi, + sys::SSize_T numBytes = IS_END); + +}; +} + +#endif diff --git a/modules/c++/io/include/io/MMapInputStream.h b/modules/c++/io/include/io/MMapInputStream.h new file mode 100644 index 000000000..1af11f111 --- /dev/null +++ b/modules/c++/io/include/io/MMapInputStream.h @@ -0,0 +1,92 @@ +/* ========================================================================= + * This file is part of io-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * io-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __IO_MMAP_INPUT_STREAM_H__ +#define __IO_MMAP_INPUT_STREAM_H__ + +#include +#include "sys/OS.h" +#include "io/SeekableStreams.h" + + +namespace io +{ + +class MMapInputStream : public SeekableInputStream +{ +public: + MMapInputStream() : mFile(NULL), mLength(0), mData(NULL), mMark(0) + {} + MMapInputStream(const std::string& inputFile, + char* flags = "r+b") : + mFile(NULL), mLength(0), mData(NULL), mMark(0) + { + open(inputFile, flags); + + } + + virtual ~MMapInputStream() + { + if (mFile) + { + close(); + } + } + + virtual void open(const std::string& fname, char* flags); + + virtual void close(); + + sys::Handle_T getHandle(); + + virtual off_t available() + { + return (mLength - mMark); + } + + virtual off_t seek(off_t off); + + virtual off_t tell() + { + return mMark; + } + + virtual ssize_t read(sys::byte* b, size_t len); + + + + +protected: + virtual void _map(); + virtual void _unmap(); + sys::OS mOs; + + FILE* mFile; + size_t mLength; + sys::byte* mData; + size_t mMark; + +}; + +} + +#endif diff --git a/modules/c++/io/include/io/NullStreams.h b/modules/c++/io/include/io/NullStreams.h new file mode 100644 index 000000000..00d6ca20d --- /dev/null +++ b/modules/c++/io/include/io/NullStreams.h @@ -0,0 +1,129 @@ +/* ========================================================================= + * This file is part of io-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * io-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __IO_NULL_STREAMS_H__ +#define __IO_NULL_STREAMS_H__ + +#include "io/InputStream.h" +#include "io/OutputStream.h" + +namespace io +{ +class NullInputStream : public InputStream +{ +public: + NullInputStream(sys::SSize_T size) : + mSize(size), + mAvailable(size) + { + } + + virtual ~NullInputStream() + { + } + + virtual sys::Off_T available() + { + return mAvailable; + } + + virtual sys::SSize_T read(sys::byte* b, sys::Size_T len) + { + sys::Size_T numToRead = + (mAvailable >= (sys::SSize_T) len ? len : (sys::Size_T) mAvailable); + + mAvailable -= (sys::SSize_T) numToRead; + + if (numToRead == 0) + throw except::IOException(Ctxt("EOF - no more data to read")); + + processBytes(b, numToRead); + return numToRead; + } + + virtual sys::SSize_T readln(sys::byte *cStr, + const sys::Size_T strLenPlusNullByte) + { + return read(cStr, strLenPlusNullByte); + } + + virtual sys::SSize_T streamTo(OutputStream& soi, + sys::SSize_T numBytes = IS_END) + { + sys::SSize_T toProcess = (numBytes == IS_END) ? numBytes : (mAvailable + >= numBytes ? numBytes : mAvailable); + mAvailable -= toProcess; + for (sys::SSize_T i = 0; i < toProcess; ++i) + soi.write(processByte()); + return toProcess; + } + +protected: + sys::SSize_T mSize; + sys::SSize_T mAvailable; + + virtual sys::byte processByte() const + { + return (sys::byte) 0; + } + virtual void processBytes(sys::byte* b, sys::Size_T len) const + { + //override for different behavior + memset(b, 0, len); + } +}; + +class NullOutputStream : public OutputStream +{ +public: + NullOutputStream() + { + } + virtual ~NullOutputStream() + { + } + + void write(sys::byte ) + { + } + + void write(const std::string& ) + { + } + + void writeln(const std::string& ) + { + } + + virtual void write(const sys::byte* , sys::Size_T ) + { + } + + virtual void flush() + { + } + +}; + +} + +#endif diff --git a/modules/c++/io/include/io/OutputStream.h b/modules/c++/io/include/io/OutputStream.h new file mode 100644 index 000000000..b87c6e9a9 --- /dev/null +++ b/modules/c++/io/include/io/OutputStream.h @@ -0,0 +1,114 @@ +/* ========================================================================= + * This file is part of io-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * io-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __IO_OUTPUT_STREAM_H__ +#define __IO_OUTPUT_STREAM_H__ + +#include "sys/Dbg.h" +#include "sys/Conf.h" + +/*! + * \file OutputStream.h + * \brief File containing class for handling output streams + * + * This file defines a java-like output interface for streams. + */ + +namespace io +{ +/*! + * \class OutputStream + * \brief Class for handling output streams + * + * This class is analogous to the corresponding java class. It is + * responsible for writes. + * + */ + +class OutputStream +{ +public: + //! Default constructor + OutputStream() + { + } + //! Destructor + virtual ~OutputStream() + { + } + + /*! + * Write one byte to the stream + * \throw IOException + */ + void write(sys::byte b) + { + write(&b, 1); + } + + /*! + * Write a string + * \param str + */ + void write(const std::string& str) + { + write((sys::byte*) str.c_str(), (sys::Size_T) str.length()); + } + + /*! + * Write a string with a newline at the end + * \param str + */ + void writeln(const std::string& str) + { + write(str); + write('\n'); + } + + /*! + * This method defines a given OutputStream. By defining, + * this method, you can define the unique attributes of an OutputStream + * inheriting class. + * \param b The byte array to write to the stream + * \param len The length of the byte array to write to the stream + * \throw IOException + */ + virtual void write(const sys::byte* b, sys::Size_T len) = 0; + + /*! + * Flush the stream if needed + */ + virtual void flush() + { + } + + /*! + * Close the stream + */ + virtual void close() + { + } + +}; +} + +#endif diff --git a/modules/c++/io/include/io/PipeStream.h b/modules/c++/io/include/io/PipeStream.h new file mode 100644 index 000000000..337629280 --- /dev/null +++ b/modules/c++/io/include/io/PipeStream.h @@ -0,0 +1,120 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __IO_PIPE_STREAM_H__ +#define __IO_PIPE_STREAM_H__ + +#include +#include +#include +#include +#include + +#include "io/InputStream.h" + +namespace io +{ + +/*! + * \class PipeStream + * \brief captures the standard output from a pipe + * and streams it to the specified location + */ +class PipeStream : InputStream +{ + +public: + + /*! + * Constructor -- + * Streams data from a pipe when available + * + * \param pipe - pipe for reading + * \param maxLineLength - max length in bytes of one line + (new line terminate) + */ + PipeStream(const std::string& cmd, size_t maxLineLength = 2501) : + InputStream(), + mExecPipe(cmd), + mCharString(new char[maxLineLength]), + mMaxLength(maxLineLength) + { + mExecPipe.run(); + } + + //! cleanup the stream if not done already + virtual ~PipeStream() + { + } + + //! closes the stream connected to the child process manually + int close() + { + return mExecPipe.closePipe(); + } + + /*! + * \func read + * \brief returns the requested size in bytes from the stream + */ + virtual sys::SSize_T read(sys::byte* b, sys::Size_T len); + + /*! + * \func readln + * \brief returns one line ending in a newline or the requested size -- + * requested size cannot be greater than the maxLength + * (default 0 means read until max or newline) + */ + virtual sys::SSize_T readln(sys::byte *cStr, + const sys::Size_T strLenPlusNullByte = 0); + + /*! + * The streaming occurs as follows: If the numBytes is IS_END, + * we want to pipe all bytes to the output handler + * Otherwise, we'll take what we've got + * We want to return the number of bytes total. + * \param soi Stream to write to + * \param numBytes The number of bytes to stream + * \throw BadPipeException + * \return The number of bytes transferred from the + * input stream to the output stream + */ + virtual sys::SSize_T streamTo(OutputStream& soi, + sys::SSize_T numBytes = IS_END); + + +protected: + + sys::ExecPipe mExecPipe; + mem::ScopedArray mCharString; + size_t mMaxLength; + +private: + + //! Noncopyable + PipeStream(const PipeStream& ); + const PipeStream& operator=(const PipeStream& ); +}; + +} + +#endif diff --git a/modules/c++/io/include/io/ProxyStreams.h b/modules/c++/io/include/io/ProxyStreams.h new file mode 100644 index 000000000..6485de004 --- /dev/null +++ b/modules/c++/io/include/io/ProxyStreams.h @@ -0,0 +1,163 @@ +/* ========================================================================= + * This file is part of io-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * io-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __IO_PROXY_STREAMS_H__ +#define __IO_PROXY_STREAMS_H__ + +#include "io/InputStream.h" +#include "io/OutputStream.h" +#include "io/NullStreams.h" + +namespace io +{ +class ProxyInputStream: public InputStream +{ +public: + ProxyInputStream(InputStream *proxy, bool ownPtr = false) : + mOwnPtr(ownPtr) + { + mProxy.reset(proxy); + } + + virtual ~ProxyInputStream() + { + if (!mOwnPtr) + mProxy.release(); + } + + virtual sys::Off_T available() + { + return mProxy->available(); + } + + virtual sys::SSize_T read(sys::byte* b, sys::Size_T len) + { + return mProxy->read(b, len); + } + + virtual void setProxy(InputStream *proxy, bool ownPtr = false) + { + if (!mOwnPtr) + mProxy.release(); + mProxy.reset(proxy); + mOwnPtr = ownPtr; + } + +protected: + std::auto_ptr mProxy; + bool mOwnPtr; +}; + +/** + * Proxies to the given OutputStream. + */ +class ProxyOutputStream: public OutputStream +{ +public: + ProxyOutputStream(OutputStream *proxy, bool ownPtr = false) : + mOwnPtr(ownPtr) + { + mProxy.reset(proxy); + } + virtual ~ProxyOutputStream() + { + if (!mOwnPtr) + mProxy.release(); + } + + using OutputStream::write; + + virtual void write(const sys::byte* b, sys::Size_T len) + { + mProxy->write(b, len); + } + + virtual void flush() + { + mProxy->flush(); + } + + virtual void close() + { + mProxy->close(); + } + + virtual void setProxy(OutputStream *proxy, bool ownPtr = false) + { + if (!mOwnPtr) + mProxy.release(); + mProxy.reset(proxy); + mOwnPtr = ownPtr; + } + +protected: + std::auto_ptr mProxy; + bool mOwnPtr; +}; + +/** + * An output stream that can be enabled/disabled (toggled). + */ +class ToggleOutputStream: public io::ProxyOutputStream +{ +public: + ToggleOutputStream(io::OutputStream *output = NULL, bool ownPtr = false) : + io::ProxyOutputStream(NULL), mPtr(output), + mNullStream(new io::NullOutputStream), mOwnPtr(ownPtr) + { + setEnabled(mPtr != NULL); + } + + virtual ~ToggleOutputStream() + { + if (mOwnPtr && mPtr) + delete mPtr; + if (mNullStream) + delete mNullStream; + } + + void setEnabled(bool flag) + { + mEnabled = flag && mPtr; + setProxy(mEnabled ? mPtr : mNullStream, false); + } + + inline bool isEnabled() const + { + return mEnabled; + } + + void close() + { + if (mEnabled && mPtr) + mPtr->close(); + setEnabled(false); + } + +protected: + io::OutputStream *mPtr, *mNullStream; + bool mOwnPtr, mEnabled; +}; + +} + +#endif diff --git a/modules/c++/io/include/io/RotatingFileOutputStream.h b/modules/c++/io/include/io/RotatingFileOutputStream.h new file mode 100644 index 000000000..fcdd06a94 --- /dev/null +++ b/modules/c++/io/include/io/RotatingFileOutputStream.h @@ -0,0 +1,63 @@ +/* ========================================================================= + * This file is part of io-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * io-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __IO_ROTATING_FILE_STREAMS_H__ +#define __IO_ROTATING_FILE_STREAMS_H__ + +#include +#include "io/CountingStreams.h" + +namespace io +{ + +/** + * An OutputStream that keeps track of the number of bytes written to the stream. + */ +class RotatingFileOutputStream: public CountingOutputStream +{ +public: + RotatingFileOutputStream(const std::string& filename, + unsigned long maxBytes = 0, + size_t backupCount = 0, int creationFlags = + sys::File::CREATE | sys::File::TRUNCATE); + + virtual ~RotatingFileOutputStream() + { + } + + using CountingOutputStream::write; + + virtual void write(const sys::byte* b, sys::Size_T len); + +protected: + std::string mFilename; + unsigned long mMaxBytes; + size_t mBackupCount; + + virtual bool shouldRollover(sys::Size_T len); + virtual void doRollover(); + +}; + +} + +#endif diff --git a/modules/c++/io/include/io/Seekable.h b/modules/c++/io/include/io/Seekable.h new file mode 100644 index 000000000..ccb81bc43 --- /dev/null +++ b/modules/c++/io/include/io/Seekable.h @@ -0,0 +1,61 @@ +/* ========================================================================= + * This file is part of io-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * io-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __IO_SEEKABLE_H__ +#define __IO_SEEKABLE_H__ + + +/*! + * Unlike in Java, we have chosen to make our InputStream and OutputStream + * classes into interfaces, not abstract classes (in the sense that we + * did not allow the mark object). This allowed us to create a third + * interface which we use for sockets, among other things: the + * BidirectionalStream and ByteStream interfaces. These have a strong + * need to behave similarly to their C++/C counterparts. + * + * As a result, where Java simply adds an offset field to the read() and + * write() methods, we felt that it would make more sense to have + * an interface for seeks. Down the line, this allows us to keep our + * sockets simple, but to implement full-fledged file IO seeks. + */ + +namespace io +{ +class Seekable +{ +public: + Seekable() + {} + virtual ~Seekable() + {} + enum Whence { CURRENT = 0, START, END }; + /*! + * Seek to an offset + * \param offset The place to seek + */ + virtual sys::Off_T seek( sys::Off_T offset, Whence whence ) = 0; + virtual sys::Off_T tell() = 0; +}; + +} + +#endif diff --git a/modules/c++/io/include/io/SeekableStreams.h b/modules/c++/io/include/io/SeekableStreams.h new file mode 100644 index 000000000..9d9d5367c --- /dev/null +++ b/modules/c++/io/include/io/SeekableStreams.h @@ -0,0 +1,83 @@ +/* ========================================================================= + * This file is part of io-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * io-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __IO_SEEKABLE_STREAMS_H__ +#define __IO_SEEKABLE_STREAMS_H__ + +#include "io/InputStream.h" +#include "io/OutputStream.h" +#include "io/BidirectionalStream.h" +#include "io/Seekable.h" + +/*! + * \file + * \brief This class is interface like and completes the Seekable interface. + * + * When I first created the Seekable interface, I overlooked the possible + * use-case that you may, in fact, wish to guarantee that your Seekable + * is also an InputStream. What you would have, then, are two derived types: + * SeekableInputStream, SeekableOutputStream, and SeekableBidirectionalStream. + * Here are the definitions, which will allow that inheritance + */ + +namespace io +{ +class SeekableInputStream : + public InputStream, public Seekable +{ +public: + SeekableInputStream() + {} + virtual ~SeekableInputStream() + {} + virtual sys::SSize_T read (sys::byte *b, sys::Size_T len) = 0; + using InputStream::streamTo; +}; + +class SeekableOutputStream : + public OutputStream, public Seekable +{ +public: + SeekableOutputStream() + {} + virtual ~SeekableOutputStream() + {} + virtual void write (const sys::byte *b, sys::Size_T len) = 0; +}; + +class SeekableBidirectionalStream : + public BidirectionalStream, public Seekable +{ +public: + SeekableBidirectionalStream() + {} + virtual ~SeekableBidirectionalStream() + {} + virtual sys::SSize_T read (sys::byte *b, sys::Size_T len) = 0; + virtual void write (const sys::byte *b, sys::Size_T len) = 0; + using InputStream::streamTo; +}; + +} + + +#endif diff --git a/modules/c++/io/include/io/Serializable.h b/modules/c++/io/include/io/Serializable.h new file mode 100644 index 000000000..f4c1c221d --- /dev/null +++ b/modules/c++/io/include/io/Serializable.h @@ -0,0 +1,75 @@ +/* ========================================================================= + * This file is part of io-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * io-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __IO_SERIALIZABLE_H__ +#define __IO_SERIALIZABLE_H__ + +#include "io/InputStream.h" +#include "io/OutputStream.h" + +/*! + * \file Serializable.h + * \brief File containing the interface for serializable objects + * + * A serializable is an object that can be written to and from a stream. + * This stream could be a socket, a file, a memory image -- even a url. + * This object has a known derived type SOAPMessage, which is concretely + * defined to handle SOAP objects + */ +namespace io +{ +/*! + * \class Serializable + * \brief Provide the interface for serializable objects + * + * A serializable is an object that can be written to and from a stream. + * This stream could be a socket, a file, a memory image -- even a url. + * This object has a known derived type SOAPMessage, which is concretely + * defined to handle SOAP objects + */ +class Serializable +{ +public: + //! Default constructor + Serializable() + { + } + //! Deconstructor + virtual ~Serializable() + { + } + + /*! + * Transfer this object into a byte stream + */ + virtual void serialize(io::OutputStream& os) = 0; + + /*! + * Unpack this input stream to the object + * \param is Stream to read object from + */ + virtual void deserialize(io::InputStream& is) = 0; + +}; +} + +#endif diff --git a/modules/c++/io/include/io/SerializableArray.h b/modules/c++/io/include/io/SerializableArray.h new file mode 100644 index 000000000..c2bf55308 --- /dev/null +++ b/modules/c++/io/include/io/SerializableArray.h @@ -0,0 +1,103 @@ +/* ========================================================================= + * This file is part of io-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * io-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __IO_SERIALIZABLE_ARRAY_H__ +#define __IO_SERIALIZABLE_ARRAY_H__ + +#include "io/Serializable.h" +#include + +namespace io +{ + +/** + * Serialize an array to/from a stream. + */ +template +class SerializableArray : public Serializable +{ +public: + + /** + * \param buf the data buffer + * \param offset the offset (in elements, not bytes) into the buffer + * \param length the length (in elements, not bytes) of the buffer + * \param skip optional stride to use + */ + SerializableArray(T* buf, sys::Size_T offset, sys::Size_T length, + sys::Size_T skip = 0) : + mBuf(buf), mOffset(offset), mLength(length), mSkip(skip) + { + } + + /** + * \param buf the data buffer + * \param length the length (in elements, not bytes) of the buffer + */ + SerializableArray(T* buf, sys::Size_T length) : + mBuf(buf), mOffset(0), mLength(length), mSkip(0) + { + } + + virtual ~SerializableArray() + { + } + + void serialize(io::OutputStream& os) + { + T* buf = (T*) (mBuf + mOffset); + if (mSkip == 0) + os.write((sys::byte*) buf, sizeof(T) * mLength); + else + { + sys::Size_T skip = mSkip + 1; + for (sys::Size_T i = 0; i < mLength; i += skip, buf += skip) + os.write((sys::byte*) buf, sizeof(T)); + } + } + + void deserialize(io::InputStream& is) + { + T* buf = (T*) (mBuf + mOffset); + if (mSkip == 0) + is.read((sys::byte*) buf, sizeof(T) * mLength); + else + { + sys::Size_T skip = mSkip + 1; + sys::byte bytes[sizeof(T)]; + for (sys::Size_T i = 0; i < mLength; ++i) + { + if (i % skip == 0) + is.read((sys::byte*) buf++, sizeof(T)); + else + is.read(bytes, sizeof(T)); + } + } + } + +protected: + T* mBuf; + sys::Size_T mOffset, mLength, mSkip; +}; +} + +#endif diff --git a/modules/c++/io/include/io/SerializableFile.h b/modules/c++/io/include/io/SerializableFile.h new file mode 100644 index 000000000..3ab75698e --- /dev/null +++ b/modules/c++/io/include/io/SerializableFile.h @@ -0,0 +1,72 @@ +/* ========================================================================= + * This file is part of io-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * io-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __IO_SERIALIZABLE_FILE_H__ +#define __IO_SERIALIZABLE_FILE_H__ + +#include "io/Serializable.h" + +/*! + * \file SerializableFile.h + */ +namespace io +{ +/*! + * \class Serializable + * \brief Provide the interface for serializable objects + * + * A serializable is an object that can be written to and from a stream. + * This stream could be a socket, a file, a memory image -- even a url. + * This object has a known derived type SOAPMessage, which is concretely + * defined to handle SOAP objects + */ +class SerializableFile: public Serializable +{ +public: + //! Default constructor + SerializableFile(const std::string& filename) : + mFilename(filename) + { + } + //! Deconstructor + virtual ~SerializableFile() + { + } + + /*! + * Transfer this object into a byte stream + */ + void serialize(io::OutputStream& os); + + /*! + * Unpack this input stream to the object + * \param is Stream to read object from + */ + void deserialize(io::InputStream& is); + +protected: + std::string mFilename; + +}; +} + +#endif diff --git a/modules/c++/io/include/io/StandardStreams.h b/modules/c++/io/include/io/StandardStreams.h new file mode 100644 index 000000000..366368dd6 --- /dev/null +++ b/modules/c++/io/include/io/StandardStreams.h @@ -0,0 +1,117 @@ +/* ========================================================================= + * This file is part of io-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * io-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __IO_STANDARD_STREAMS_H__ +#define __IO_STANDARD_STREAMS_H__ + +#include "io/OutputStream.h" +#include "except/Exception.h" +#include "sys/Mutex.h" + +#if defined(_REENTRANT) + +# define _STDSTREAM_DECLARE_MUTEX_SEMICOLON_ static sys::Mutex mCritSection; +# define _STDERR_DEFINE_MUTEX_SEMICOLON_ sys::Mutex io::StandardErrStream::mCritSection; +# define _STDOUT_DEFINE_MUTEX_SEMICOLON_ sys::Mutex io::StandardOutStream::mCritSection; +# define _STDSTREAM_BEGIN_CS_SEMICOLON_ mCritSection.lock(); +# define _STDSTREAM_END_CS_SEMICOLON_ mCritSection.unlock(); + +#else + +# define _STDSTREAM_DECLARE_MUTEX_SEMICOLON_ +# define _STDERR_DEFINE_MUTEX_SEMICOLON_ +# define _STDOUT_DEFINE_MUTEX_SEMICOLON_ +# define _STDSTREAM_BEGIN_CS_SEMICOLON_ +# define _STDSTREAM_END_CS_SEMICOLON_ + +#endif +/*! + * \file + * \brief Defines classes for writing to stderr and stdout + */ +namespace io +{ +/*! + * \class StandardOutStream + * \brief Class for writing output streams to stdout + */ +class StandardOutStream : public OutputStream +{ + +public: + //! Default constructor + StandardOutStream() + {} + + /*! + * This method defines a write to stdout. + * \param b The byte array to write to the stream + * \param len the length of bytes to read + * \throw except::IOException + */ + virtual void write(const sys::byte* b, sys::Size_T len); + + /*! + * Flushes stdout + */ + virtual void flush(); + + using OutputStream::write; + using OutputStream::writeln; + +protected: + _STDSTREAM_DECLARE_MUTEX_SEMICOLON_ + +}; + +/*! + * \class StandardErrStream + * \brief Class for writing output streams to stderr + */ +class StandardErrStream : public OutputStream +{ + +public: + //! Default constructor + StandardErrStream() + {} + + /*! + * This method defines a write to stderr. + * \param b The byte array to write to the stream + * \param len the length of bytes to read + * \throw except::IOException + */ + virtual void write(const sys::byte* b, sys::Size_T len); + + /*! + * Flushes stderr + */ + virtual void flush(); + +protected: + _STDSTREAM_DECLARE_MUTEX_SEMICOLON_ + +}; + +} +#endif diff --git a/modules/c++/io/include/io/StringStream.h b/modules/c++/io/include/io/StringStream.h new file mode 100644 index 000000000..e187dd4d1 --- /dev/null +++ b/modules/c++/io/include/io/StringStream.h @@ -0,0 +1,113 @@ +/* ========================================================================= + * This file is part of io-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * io-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __IO_STRING_STREAM_H__ +#define __IO_STRING_STREAM_H__ + +/*! \file StringStream.h + * \brief A stream interface to the std::stringstream from C++ STL. + * + * String streams are very useful. They are even more useful with cafe + * streaming capabilities. The capabilities are added by making the class + * inherit from a stream -- a class that can pipe information back and + * forth to other streams. + */ + +#include +#include "io/BidirectionalStream.h" +#include "io/ByteStream.h" +#include "sys/Conf.h" +#include "io/SeekableStreams.h" + +namespace io +{ +/*! + * The StringStream class is the cafe interface to std::stringstream. + * Added capabilities allow it to send and receive information quickly + * and easily to any other stream-inheriting class. + */ +class StringStream : public SeekableBidirectionalStream +{ +public: + + //! Default constructor. + StringStream() + {} + + //! Destructor. + virtual ~StringStream() + {} + + /*! + * Returns the number of available bytes to read from the stream + * \return the number of available bytes + */ + virtual sys::Off_T available(); + + /*! + * This method is inherited from OutputStream. It must be overloaded + * for the class to work properly. + * \param data The data to write + * \param size The size of the data to write + */ + virtual void write(const sys::byte* data, sys::Size_T size); + + virtual void write(const std::string& s); + + /*! + * This is the read method from ByteStream. It has an added member + * for GCC < 3.0, and for sun forte compilers. The older compilers + * have some problems with their read/write operations for stringstreams. + * If you have an old version of gcc, or sun, make sure that either + * __GCC_LESS_THAN_3_0 or __SUN is defined, and the hack will be used + * (it will probably have worse performance, however). + * \param data The data to read + * \param size The size of the data to read + * \return Size. + */ + virtual sys::SSize_T read(sys::byte *data, sys::Size_T size); + + /*! + * Returns the stringstream associated with this StringStream + * \return the stringstream + */ + const std::stringstream& stream() const + { + return mStream.stream(); + } + + sys::Off_T tell() + { + return mStream.tell(); + } + + sys::Off_T seek(sys::Off_T offset, Whence whence) + { + return mStream.seek(offset, whence); + } + +protected: + ByteStream mStream; + +}; +} +#endif //__STRING_STREAM_H__ diff --git a/modules/c++/io/source/ByteStream.cpp b/modules/c++/io/source/ByteStream.cpp new file mode 100644 index 000000000..c8b3d7efc --- /dev/null +++ b/modules/c++/io/source/ByteStream.cpp @@ -0,0 +1,66 @@ +/* ========================================================================= + * This file is part of io-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * io-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include "io/ByteStream.h" + +sys::Off_T io::ByteStream::available() +{ + sys::Off_T where = (sys::Off_T)mData.tellg(); + + mData.seekg( 0, std::ios::end ); + sys::Off_T until = (sys::Off_T)mData.tellg(); + + mData.seekg( where, std::ios::beg ); + return (until - where); +} + +void io::ByteStream::write(const sys::byte *b, sys::Size_T size) +{ + mData.write((const char*)b, size); +} + +sys::SSize_T io::ByteStream::read(sys::byte *b, sys::Size_T len) +{ + sys::Off_T maxSize = available(); + if (maxSize <= 0) return io::InputStream::IS_END; + + if (maxSize < (sys::Off_T)len) + len = maxSize; + + if (len <= 0) return 0; + +#if defined(__SUNPRO_CC) && (__SUNPRO_CC == 0x530) + sys::SSize_T bytesRead(0); + while (bytesRead < len && mData.good()) + { + b[bytesRead++] = mData.get(); + } + len = bytesRead; +#else + mData.read((char *)b, len); +#endif + // Could be problem if streams are broken + // alternately could return gcount in else + // case above + return len; +} + diff --git a/modules/c++/io/source/FileInputStreamIOS.cpp b/modules/c++/io/source/FileInputStreamIOS.cpp new file mode 100644 index 000000000..d15dafc15 --- /dev/null +++ b/modules/c++/io/source/FileInputStreamIOS.cpp @@ -0,0 +1,134 @@ +/* ========================================================================= + * This file is part of io-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * io-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include "io/FileInputStreamIOS.h" + +#if defined(USE_IO_STREAMS) + +io::FileInputStreamIOS::FileInputStreamIOS(const char* inputFile, + std::ios::openmode mode) +{ + open(inputFile, mode); +} + +io::FileInputStreamIOS::FileInputStreamIOS(const std::string& inputFile, + std::ios::openmode mode) +{ + open(inputFile.c_str(), mode); +} + +/*! + * Returns the number of bytes that can be read + * without blocking by the next caller of a method for this input + * + * \throw except::IOException + * \return number of bytes which are readable + * + */ +sys::Off_T io::FileInputStreamIOS::available() +{ + sys::Off_T where = mFStream.tellg(); + mFStream.seekg(0, std::ios::end); + sys::Off_T until = mFStream.tellg(); + mFStream.seekg(where, std::ios::beg); + return (until - where); +} + +sys::Off_T io::FileInputStreamIOS::tell() +{ + return mFStream.tellg(); +} + +sys::Off_T io::FileInputStreamIOS::seek(sys::Off_T offset, Whence whence) +{ + std::ios::seekdir flags; + switch (whence) + { + case START: + flags = std::ios::beg; + break; + + case END: + flags = std::ios::end; + break; + + default: + flags = std::ios::cur; + + } + + mFStream.seekg(offset, flags); + return tell(); +} + + +bool io::FileInputStreamIOS::isOpen() +{ + return mFStream.is_open() && mFStream.good(); +} +void io::FileInputStreamIOS::open(const char *file, + std::ios::openmode mode) +{ + mFStream.open(file, mode); + if (!isOpen()) + throw except::IOException(Ctxt( + FmtX( + "File %s could not be opened for reading", + file) + ) + ); +} +void io::FileInputStreamIOS::close() +{ + mFStream.close(); +} + +sys::SSize_T io::FileInputStreamIOS::read(sys::byte* b, sys::Size_T len) +{ + ::memset(b, 0, len); + sys::Off_T avail = available(); + if (mFStream.eof() || avail <= 0) return io::InputStream::IS_EOF; + if (len < (sys::Size_T)avail) + avail = len; + + if (avail > 0) + { + sys::SSize_T bytesRead(0); + // There is a 'huge-gantic' bug in Forte 6.2 + // in which 'read()' reads the first character twice +#if defined(__SUNPRO_CC) && (__SUNPRO_CC == 0x530) + + while (bytesRead < avail && mFStream.good()) + { + b[bytesRead++] = mFStream.get(); + } +#else + mFStream.read((char *)b, avail); + bytesRead = mFStream.gcount(); +#endif + return bytesRead; + } + + return 0; +} + +#endif diff --git a/modules/c++/io/source/FileInputStreamOS.cpp b/modules/c++/io/source/FileInputStreamOS.cpp new file mode 100644 index 000000000..93b135181 --- /dev/null +++ b/modules/c++/io/source/FileInputStreamOS.cpp @@ -0,0 +1,62 @@ +/* ========================================================================= + * This file is part of io-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * io-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include "io/FileInputStreamOS.h" + +#if !defined(USE_IO_STREAMS) + +/*! + * Returns the number of bytes that can be read + * without blocking by the next caller of a method for this input + * + * \throw except::IOException + * \return number of bytes which are readable + * + */ +sys::Off_T io::FileInputStreamOS::available() +{ + sys::Off_T where = mFile.getCurrentOffset(); + mFile.seekTo(0, sys::File::FROM_END); + sys::Off_T until = mFile.getCurrentOffset(); + mFile.seekTo(where, sys::File::FROM_START); + + return (until - where); +} + + +sys::SSize_T io::FileInputStreamOS::read(sys::byte* b, sys::Size_T len) +{ + ::memset(b, 0, len); + sys::Off_T avail = available(); + if (!avail) + return io::InputStream::IS_EOF; + if (len > (sys::Size_T)avail) + len = (sys::Size_T)avail; + + mFile.readInto((char *)b, len); + return (sys::SSize_T)len; + +} + + +#endif + diff --git a/modules/c++/io/source/FileOutputStreamIOS.cpp b/modules/c++/io/source/FileOutputStreamIOS.cpp new file mode 100644 index 000000000..ee7544a59 --- /dev/null +++ b/modules/c++/io/source/FileOutputStreamIOS.cpp @@ -0,0 +1,119 @@ +/* ========================================================================= + * This file is part of io-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * io-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include "io/FileOutputStreamIOS.h" + +#if defined(USE_IO_STREAMS) + +io::FileOutputStreamIOS::FileOutputStreamIOS(const char* outputFile, + int creationFlags) +{ + std::ios::openmode mode = std::ios::out; + + if ( (creationFlags & sys::File::TRUNCATE) != sys::File::TRUNCATE || + (creationFlags & std::ios::app) == std::ios::app) + mode |= std::ios::app; + + open(outputFile, mode); +} + +io::FileOutputStreamIOS::FileOutputStreamIOS(const std::string& outputFile, + int creationFlags) +{ + std::ios::openmode mode = std::ios::out; + + if ( (creationFlags & sys::File::TRUNCATE) != sys::File::TRUNCATE || + (creationFlags & std::ios::app) == std::ios::app) + mode |= std::ios::app; + + open(outputFile.c_str(), mode); +} + +bool io::FileOutputStreamIOS::isOpen() +{ + return mFStream.is_open() && mFStream.good(); +} + +void io::FileOutputStreamIOS::open(const char *file, + std::ios::openmode mode) +{ + mFStream.open(file, mode); + if (!isOpen()) + { + throw except::Error(Ctxt(FmtX("File could not be opened: %s", file))); + } +} + +void io::FileOutputStreamIOS::close() +{ + if (!isOpen()) return ; + mFStream.close(); + + if (mFStream.is_open()) + { + throw except::IOException(Ctxt("File could not be closed")); + } +} + +/*! + * This method defines a given OutputStream. By defining, + * this method, you can define the unique attributes of an OutputStream + * inheriting class. + * \param b The byte array to write to the stream + * \param len the length of bytes to write + * \throw IOException + */ +void io::FileOutputStreamIOS::write(const sys::byte* b, sys::Size_T len) +{ + //std::string s((const char*)b, len); + //EVAL(s.c_str()); + mFStream.write((const char*)b, len); +} + + +sys::Off_T io::FileOutputStreamIOS::seek(sys::Off_T offset, + io::Seekable::Whence whence) +{ + std::ios::seekdir dir; + switch (whence) + { + case io::Seekable::START: + dir = std::ios::beg; + break; + case io::Seekable::END: + dir = std::ios::end; + break; + default: + dir = std::ios::cur; + break; + } + + mFStream.seekp(offset, dir); + return tell(); +} + +sys::Off_T io::FileOutputStreamIOS::tell() +{ + return mFStream.tellp(); +} + +#endif diff --git a/modules/c++/io/source/FileOutputStreamOS.cpp b/modules/c++/io/source/FileOutputStreamOS.cpp new file mode 100644 index 000000000..9ce3d2e64 --- /dev/null +++ b/modules/c++/io/source/FileOutputStreamOS.cpp @@ -0,0 +1,90 @@ +/* ========================================================================= + * This file is part of io-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * io-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include "io/FileOutputStreamOS.h" + +#if !defined(USE_IO_STREAMS) + +io::FileOutputStreamOS::FileOutputStreamOS(const std::string& str, + int creationFlags) +{ + mFile.create(str, sys::File::WRITE_ONLY, creationFlags); + +} + +void io::FileOutputStreamOS::create(const std::string& str, + int creationFlags) +{ + mFile.create(str, sys::File::WRITE_ONLY, creationFlags); + if (!isOpen()) + { + throw except::FileNotFoundException( + std::string("File could not be opened: ") + str + ); + } +} + + +/*! + * This method defines a given OutputStream. By defining, + * this method, you can define the unique attributes of an OutputStream + * inheriting class. + * \param b The byte array to write to the stream + * \param len the length of bytes to write + * \throw IOException + */ +void io::FileOutputStreamOS::write(const sys::byte* b, sys::Size_T len) +{ + mFile.writeFrom((const char*)b, len); +} + +void io::FileOutputStreamOS::flush() +{ + mFile.flush(); +} + +sys::Off_T io::FileOutputStreamOS::seek(sys::Off_T offset, + io::Seekable::Whence whence) +{ + int fileWhence; + switch (whence) + { + case io::Seekable::START: + fileWhence = sys::File::FROM_START; + break; + case io::Seekable::END: + fileWhence = sys::File::FROM_END; + break; + default: + fileWhence = sys::File::FROM_CURRENT; + break; + } + return mFile.seekTo(offset, fileWhence); +} + +sys::Off_T io::FileOutputStreamOS::tell() +{ + return mFile.getCurrentOffset(); +} + +#endif + diff --git a/modules/c++/io/source/FileUtils.cpp b/modules/c++/io/source/FileUtils.cpp new file mode 100644 index 000000000..83f1f0518 --- /dev/null +++ b/modules/c++/io/source/FileUtils.cpp @@ -0,0 +1,105 @@ +/* ========================================================================= + * This file is part of io-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * io-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include "io/FileUtils.h" +#include "io/FileOutputStream.h" + +std::string io::FileUtils::createFile(std::string dirname, + std::string filename, bool overwrite) throw (except::IOException) +{ + sys::OS os; + + if (!os.exists(dirname)) + throw except::IOException(Ctxt(FmtX("Directory does not exist: %s", + dirname.c_str()))); + + str::trim(filename); + + bool emptyName = filename.empty(); + //to protect against full paths being passed in + filename = emptyName ? filename : sys::Path::basename(filename); + + std::string outFilename = sys::Path::joinPaths(dirname, filename); + if (emptyName || (os.exists(outFilename) && !overwrite)) + { + std::string ext = ""; + if (!emptyName) + { + sys::Path::StringPair nameExt = sys::Path::splitExt(filename); + filename = nameExt.first; + ext = nameExt.second; + + int count = 0; + while (os.exists(outFilename)) + { + std::string base = filename + "-" + str::toString(++count); + outFilename = sys::Path::joinPaths(dirname, base); + if (!ext.empty()) + { + outFilename += ext; + } + } + } + else + { + //just create a temp filename + outFilename = os.getTempName(dirname); + } + //now, touch it + io::FileUtils::touchFile(outFilename); + } + return outFilename; +} + +void io::FileUtils::touchFile(std::string filename) throw (except::IOException) +{ + sys::OS os; + if (os.exists(filename)) + { + io::FileOutputStream f(filename, sys::File::EXISTING + | sys::File::WRITE_ONLY); + f.close(); + } + else + { + io::FileOutputStream f(filename, sys::File::CREATE + | sys::File::TRUNCATE); + f.close(); + } +} + +void io::FileUtils::forceMkdir(std::string dirname) throw (except::IOException) +{ + sys::OS os; + if (os.exists(dirname)) + { + if (!os.isDirectory(dirname)) + throw except::IOException( + Ctxt( + "Cannot create directory - file already exists")); + } + else + { + if (!os.makeDirectory(dirname)) + throw except::IOException(Ctxt("Cannot create directory")); + } +} diff --git a/modules/c++/io/source/InputStream.cpp b/modules/c++/io/source/InputStream.cpp new file mode 100644 index 000000000..6f7ab9b14 --- /dev/null +++ b/modules/c++/io/source/InputStream.cpp @@ -0,0 +1,75 @@ +/* ========================================================================= + * This file is part of io-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * io-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include "io/InputStream.h" + +sys::SSize_T io::InputStream::streamTo(io::OutputStream& soi, sys::SSize_T bytesToPipe) +{ + + // In this event, we want to find the end of file, + // and pipe that many bytes + if (bytesToPipe == io::InputStream::IS_END) + { + bytesToPipe = available(); + } + + // Do some maintenance checking to make sure our state is as expected + sys::SSize_T bytesRead = 0; + sys::SSize_T totalBytesTransferred = 0; + + int sizeOfVec = (bytesToPipe <= DEFAULT_CHUNK_SIZE) ? (bytesToPipe) : (DEFAULT_CHUNK_SIZE); + sys::byte vec[DEFAULT_CHUNK_SIZE]; + memset(vec, 0, DEFAULT_CHUNK_SIZE); + + // While we dont have end of (stream), read into the vec, use the + // vec to write the pipe, and reset the vec + // This could be easily done using a char vec as well + while ( ((bytesRead = read(vec, sizeOfVec)) != io::InputStream::IS_EOF) && + (totalBytesTransferred != bytesToPipe)) + { + + soi.write(vec, bytesRead); + totalBytesTransferred += bytesRead; + memset(vec, 0, DEFAULT_CHUNK_SIZE); + sizeOfVec = (bytesToPipe - totalBytesTransferred <= DEFAULT_CHUNK_SIZE) ? + (bytesToPipe - totalBytesTransferred) : (DEFAULT_CHUNK_SIZE); + } + // Return the number of bytes we piped + return totalBytesTransferred; +} + +sys::SSize_T io::InputStream::readln(sys::byte *cStr, const sys::Size_T strLenPlusNullByte) +{ + // Put a null byte at the end by default + ::memset(cStr, 0, strLenPlusNullByte); + // Read length - 1 bytes, because we need a null-byte + size_t i; + for (i = 0; i < strLenPlusNullByte - 1; i++) + { + // If we got nothing + if (read(cStr + i, 1) == -1) return -1; + // Otherwise, if we got newline, return that we read i + 1 + if (*(cStr + i) == '\n') return i + 1; + // Otherwise, append c; + } + return (sys::SSize_T)i; +} diff --git a/modules/c++/io/source/MMapInputStream.cpp b/modules/c++/io/source/MMapInputStream.cpp new file mode 100644 index 000000000..2642fbd9e --- /dev/null +++ b/modules/c++/io/source/MMapInputStream.cpp @@ -0,0 +1,86 @@ +/* ========================================================================= + * This file is part of io-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * io-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include "io/MMapInputStream.h" + +void io::MMapInputStream::open(const std::string& fname, char* flags) +{ + mLength = mOs.getSize(fname); + // std::cout << mLength << std::endl; + mFile = fopen(fname.c_str(), "r"); + if (!mFile) + throw sys::SystemException(FmtX("Failure while opening file: %s", fname.c_str())); + + _map(); + +} + +void io::MMapInputStream::close() +{ + _unmap(); + fclose(mFile); + mFile = NULL; +} + +void io::MMapInputStream::_map() +{ + sys::Handle_T handle = getHandle(); + mData = (sys::byte*)mOs.mapFile(handle, mLength, PROT_READ, MAP_SHARED, 0); +} +void io::MMapInputStream::_unmap() +{ + // std::cout << "Unmapping file... "; + mOs.unmapFile(mData, mLength); + mData = NULL; + // std::cout << "done!" << std::endl; +} + +sys::Handle_T io::MMapInputStream::getHandle() +{ + if (!mFile) throw except::NullPointerReference(Ctxt("Uninitialized memory mapped file stream!")); + return ::fileno(mFile); +} + + + +long io::MMapInputStream::seek(long off) +{ + long where = mMark; + mMark = off; + return mMark - where; +} + + +long io::MMapInputStream::read(sys::byte* b, long len) +{ + int size = available(); + // std::cout << "Available: " << size << std::endl; + // std::cout << "Len: " << len << std::endl; + + if (len < size) + size = len; + memcpy(b, &mData[mMark], size); + mMark += size; + // std::cout << "Used: " << size << std::endl; + return size; +} + diff --git a/modules/c++/io/source/PipeStream.cpp b/modules/c++/io/source/PipeStream.cpp new file mode 100644 index 000000000..97a761e5f --- /dev/null +++ b/modules/c++/io/source/PipeStream.cpp @@ -0,0 +1,118 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ +#include "io/PipeStream.h" + +using namespace io; + +sys::SSize_T io::PipeStream::read(sys::byte *cStr, + const sys::Size_T strLenPlusNullByte) +{ + size_t bytesLeft = strLenPlusNullByte; + char* tmp = cStr; + while (bytesLeft) + { + sys::SSize_T bytesRead = readln(tmp, bytesLeft); + if (bytesRead != -1) + { + // take off null terminated byte in count + bytesLeft -= bytesRead - 1; + tmp += bytesRead - 1; + } + else + { + // null terminate the array + tmp[0] = 0; + return (bytesLeft + 1) - strLenPlusNullByte; + } + } + return -1; +} + +sys::SSize_T io::PipeStream::readln(sys::byte *cStr, + const sys::Size_T strLenPlusNullByte) +{ + // validation + sys::Size_T readLength = strLenPlusNullByte; + if (!readLength || readLength > mMaxLength) + { + readLength = mMaxLength; + } + + // get the next line or return null + while (!feof(mExecPipe.getPipe()) && + fgets(cStr, (int)readLength, + mExecPipe.getPipe()) != NULL) + { + // add 1 because of null termination + return strlen(cStr) + 1; + } + + // no byte read -- + // either none left or eof reached + return -1; +} + +sys::SSize_T io::PipeStream::streamTo(OutputStream& soi, + sys::SSize_T numBytes) +{ + size_t totalBytesRead = 0; + if (numBytes == IS_END) + { + // read line by line + while (!feof(mExecPipe.getPipe()) && + fgets(mCharString.get(), (int)mMaxLength, + mExecPipe.getPipe()) != NULL) + { + size_t bytesRead = strlen(mCharString.get()); + + // write without null termination + soi.write(mCharString.get(), bytesRead - 1); + totalBytesRead += bytesRead - 1; + } + } + else + { + size_t bytesLeft = numBytes; + while (bytesLeft) + { + // read line by line + if (!feof(mExecPipe.getPipe()) && + fgets(mCharString.get(), (int)mMaxLength, + mExecPipe.getPipe()) != NULL) + { + size_t bytesRead = strlen(mCharString.get()); + + // write without null termination + soi.write(mCharString.get(), bytesRead - 1); + totalBytesRead += bytesRead - 1; + + // subtract 1 because we want to have room for the null character + bytesLeft = numBytes - totalBytesRead - 1; + } + } + } + + // null terminate the stream + soi.write(0); + return totalBytesRead + 1; +} + diff --git a/modules/c++/io/source/RotatingFileOutputStream.cpp b/modules/c++/io/source/RotatingFileOutputStream.cpp new file mode 100644 index 000000000..7ef396214 --- /dev/null +++ b/modules/c++/io/source/RotatingFileOutputStream.cpp @@ -0,0 +1,95 @@ +/* ========================================================================= + * This file is part of io-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * io-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include "io/RotatingFileOutputStream.h" +#include "io/FileOutputStream.h" + +io::RotatingFileOutputStream::RotatingFileOutputStream( + const std::string& filename, + unsigned long maxBytes, + size_t backupCount, + int creationFlags) : + io::CountingOutputStream(new io::FileOutputStream(filename, creationFlags), + true), mFilename(filename), mMaxBytes(maxBytes), + mBackupCount(backupCount) +{ + mByteCount = ((io::FileOutputStream*) mProxy.get())->tell(); + if (shouldRollover(0)) + doRollover(); +} + +bool io::RotatingFileOutputStream::shouldRollover(sys::Size_T len) +{ + if (mMaxBytes > 0) + { + // first check if we are at the beginning of the file + // if one log message overflows our max bytes, we'll just write it + // the other option is to not write it at all - at least this way we + // track it + if (mByteCount == 0 && len > mMaxBytes) + return false; + + // otherwise, if this message puts us over, we rollover + if (mByteCount + len > mMaxBytes) + return true; + } + return false; +} + +void io::RotatingFileOutputStream::doRollover() +{ + io::FileOutputStream* fos = (io::FileOutputStream*) mProxy.get(); + fos->close(); + sys::OS os; + + if (mBackupCount > 0) + { + for (int i = mBackupCount - 1; i > 0; --i) + { + std::stringstream curName; + curName << mFilename << "." << i; + std::stringstream nextName; + nextName << mFilename << "." << (i + 1); + if (os.exists(curName.str())) + { + if (os.exists(nextName.str())) + { + os.remove(nextName.str()); + } + os.move(curName.str(), nextName.str()); + } + } + std::string curName = mFilename + ".1"; + if (os.exists(curName)) + os.remove(curName); + os.move(mFilename, curName); + } + mProxy.reset(new io::FileOutputStream(mFilename, sys::File::CREATE)); + mByteCount = 0; +} + +void io::RotatingFileOutputStream::write(const sys::byte* b, sys::Size_T len) +{ + if (shouldRollover(len)) + doRollover(); + io::CountingOutputStream::write(b, len); +} diff --git a/modules/c++/io/source/SerializableFile.cpp b/modules/c++/io/source/SerializableFile.cpp new file mode 100644 index 000000000..3f0bf4f30 --- /dev/null +++ b/modules/c++/io/source/SerializableFile.cpp @@ -0,0 +1,39 @@ +/* ========================================================================= + * This file is part of io-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * io-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include "io/SerializableFile.h" +#include "io/FileInputStream.h" +#include "io/FileOutputStream.h" + +void io::SerializableFile::serialize(io::OutputStream& os) +{ + io::FileInputStream fin(mFilename); + fin.streamTo(os); + fin.close(); +} + +void io::SerializableFile::deserialize(io::InputStream& is) +{ + io::FileOutputStream fout(mFilename); + is.streamTo(fout); + fout.close(); +} diff --git a/modules/c++/io/source/StandardStreams.cpp b/modules/c++/io/source/StandardStreams.cpp new file mode 100644 index 000000000..73720100e --- /dev/null +++ b/modules/c++/io/source/StandardStreams.cpp @@ -0,0 +1,65 @@ +/* ========================================================================= + * This file is part of io-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * io-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include "io/StandardStreams.h" + +_STDERR_DEFINE_MUTEX_SEMICOLON_ +_STDOUT_DEFINE_MUTEX_SEMICOLON_ +void io::StandardOutStream::write(const sys::byte* b, sys::Size_T len) +{ + _STDSTREAM_BEGIN_CS_SEMICOLON_ + std::cout.write((const char*)b, len); + _STDSTREAM_END_CS_SEMICOLON_ + //int returnVal = fwrite(b, len, len, stdout); + if (!std::cout.good()) + throw except::IOException( + Ctxt( + FmtX("std::cout stream is bad after requested write: (%d)", + len)) ); +} + +void io::StandardOutStream::flush() +{ + _STDSTREAM_BEGIN_CS_SEMICOLON_ + std::cout.flush(); + _STDSTREAM_END_CS_SEMICOLON_ +} + +void io::StandardErrStream::write(const sys::byte* b, sys::Size_T len) +{ + _STDSTREAM_BEGIN_CS_SEMICOLON_ + std::cerr.write((const char*)b, len); + //int returnVal = fwrite(b, len, len, stderr); + _STDSTREAM_END_CS_SEMICOLON_ + if (!std::cerr.good()) + throw except::IOException( + Ctxt( + FmtX("std::cerr stream is bad after requested write: (%d)", + len) ) ); +} + +void io::StandardErrStream::flush() +{ + _STDSTREAM_BEGIN_CS_SEMICOLON_ + std::cerr.flush(); + _STDSTREAM_END_CS_SEMICOLON_ +} diff --git a/modules/c++/io/source/StringStream.cpp b/modules/c++/io/source/StringStream.cpp new file mode 100644 index 000000000..0677dafb7 --- /dev/null +++ b/modules/c++/io/source/StringStream.cpp @@ -0,0 +1,43 @@ +/* ========================================================================= + * This file is part of io-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * io-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include "io/StringStream.h" + +sys::Off_T io::StringStream::available() +{ + return mStream.available(); +} + +void io::StringStream::write(const sys::byte* data, sys::Size_T size) +{ + mStream.write(data, size); +} + +void io::StringStream::write(const std::string& s) +{ + mStream.write((sys::byte*)s.c_str(), (sys::Size_T)s.length()); +} + +sys::SSize_T io::StringStream::read(sys::byte *data, sys::Size_T size) +{ + return mStream.read(data, size); +} diff --git a/modules/c++/io/tests/PipeStreamTest.cpp b/modules/c++/io/tests/PipeStreamTest.cpp new file mode 100644 index 000000000..1e9609696 --- /dev/null +++ b/modules/c++/io/tests/PipeStreamTest.cpp @@ -0,0 +1,71 @@ +/* ========================================================================= + * This file is part of io-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * io-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include +#include +#include + +int main(int argc, char **argv) +{ + try + { + std::string cmd; + + if (argc > 1) + cmd = std::string(argv[1]); + else + cmd = "echo Scream!"; + + io::PipeStream ps(cmd); + + io::StandardOutStream stdo; + ps.streamTo(stdo); + stdo.writeln(""); + stdo.close(); + + if (ps.close() != 0) + { + std::cout << "Child Process Successful but Internally Failed!" << + std::endl; + } + else + { + std::cout << "Child Process Successful!" << std::endl; + } + } + catch (const except::Throwable& ex) + { + std::cerr << "Caught C++ exception: " << + ex.getMessage() << std::endl; + } + catch (const std::exception& ex) + { + std::cerr << "Caught standard exception from " << + ex.what() << std::endl; + } + catch (...) + { + std::cerr << "Caught unnamed Unwanted exception" << std::endl; + } + + return 0; +} diff --git a/modules/c++/io/tests/byteStreamTest1.cpp b/modules/c++/io/tests/byteStreamTest1.cpp new file mode 100644 index 000000000..b344c522d --- /dev/null +++ b/modules/c++/io/tests/byteStreamTest1.cpp @@ -0,0 +1,45 @@ +/* ========================================================================= + * This file is part of io-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * io-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include +using namespace io; + +int main(int argc, char *argv[]) +{ + if (argc != 3) + { + fprintf(stderr, "Usage: %s \n", argv[0]); + return -1; + } + + FileInputStream iStream(argv[1]); + FileOutputStream oStream(argv[2]); + ByteStream bStream; + + iStream.streamTo(bStream); + bStream.streamTo(oStream); + + iStream.close(); + oStream.close(); + + return 0; +} diff --git a/modules/c++/io/tests/byteStreamTest2.cpp b/modules/c++/io/tests/byteStreamTest2.cpp new file mode 100644 index 000000000..900a29f3d --- /dev/null +++ b/modules/c++/io/tests/byteStreamTest2.cpp @@ -0,0 +1,56 @@ +/* ========================================================================= + * This file is part of io-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * io-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include +using namespace std; + +#include +using namespace io; + +#include +using namespace sys; + + + +int main(int argc, char *argv[]) +{ + std::string input("abcdefghijklmnopqrstuvwxyz"); + char buffer[32]; + memset(buffer, 0, 32); + + ByteStream bStream; + bStream.write((const sys::byte*)input.c_str(), 5); + bStream.read((sys::byte*)buffer, 3); + cout << "1:" << buffer << endl; + + memset(buffer, 0, 32); + bStream.write((const sys::byte*)input.c_str(), 10); + bStream.read((sys::byte*)buffer, 11); + cout << "2:" << buffer << endl; + + memset(buffer, 0, 32); + bStream.read((sys::byte*)buffer, 100); + cout << "3:" << buffer << endl; + + + return 0; +} diff --git a/modules/c++/io/tests/ioTest1.cpp b/modules/c++/io/tests/ioTest1.cpp new file mode 100644 index 000000000..8ba28cee5 --- /dev/null +++ b/modules/c++/io/tests/ioTest1.cpp @@ -0,0 +1,57 @@ +/* ========================================================================= + * This file is part of io-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * io-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include +#include +#include +using namespace io; +using namespace except; +using namespace std; + +int main(int argc, char **argv) +{ + try + { + if (argc != 3) + { + throw Exception(Ctxt(FmtX("Usage: %s ", + argv[0]))); + } + + FileInputStream fis(argv[1]); + FileOutputStream fos(argv[2]); + fis.streamTo(fos); + + fis.close(); + fos.close(); + } + catch (Throwable& t) + { + cout << "Caught throwable: " << t.toString() << std::endl; + } + catch (...) + { + cout << "Caught unnamed exception" << endl; + } + + return 0; +} diff --git a/modules/c++/io/tests/ioTest2.cpp b/modules/c++/io/tests/ioTest2.cpp new file mode 100644 index 000000000..be7f9e3a9 --- /dev/null +++ b/modules/c++/io/tests/ioTest2.cpp @@ -0,0 +1,60 @@ +/* ========================================================================= + * This file is part of io-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * io-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include +#include +using namespace except; +using namespace io; +using namespace std; + +class Copy +{ +public: + static void run(const char* src, const char* dest) + { + FileInputStream in(src); + FileOutputStream out(dest); + int c; + unsigned char buf[25] = ""; + + while ((c = in.read((sys::byte*) buf, 25)) != FileInputStream::IS_EOF) + out.write((sys::byte*) buf, c); + in.close(); + out.close(); + } +}; + +int main(int argc, char **argv) +{ + try + { + if (argc != 3) + throw Exception(Ctxt("argc != 3")); + + Copy::run(argv[1], argv[2]); + } + catch (Exception& e) + { + cout << e.toString() << endl; + } + +} diff --git a/modules/c++/io/tests/ioTest3.cpp b/modules/c++/io/tests/ioTest3.cpp new file mode 100644 index 000000000..d0f1c3d19 --- /dev/null +++ b/modules/c++/io/tests/ioTest3.cpp @@ -0,0 +1,59 @@ +/* ========================================================================= + * This file is part of io-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * io-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include +#include +using namespace io; +using namespace except; +using namespace std; + +class Copy +{ +public: + static void run(const char* src, const char* dest) + { + FileInputStream in(src); + FileOutputStream out(dest); + ByteStream bs; + + in.streamTo(bs); + bs.streamTo(out); + + in.close(); + out.close(); + } +}; + +int main(int argc, char **argv) +{ + try + { + if (argc != 3) + throw Exception(Ctxt(FmtX("Usage: %s ", argv[0]))); + + Copy::run(argv[1], argv[2]); + } + catch (Exception& e) + { + cout << e.toString() << endl; + } +} diff --git a/modules/c++/io/tests/ioTest4.cpp b/modules/c++/io/tests/ioTest4.cpp new file mode 100644 index 000000000..205e5ff12 --- /dev/null +++ b/modules/c++/io/tests/ioTest4.cpp @@ -0,0 +1,67 @@ +/* ========================================================================= + * This file is part of io-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * io-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include +#include +#include + +using namespace sys; +using namespace io; +using namespace except; +using namespace std; + +class Copy +{ +public: + static void run(const char* src, const char* dest) + { + io::FileInputStream in(src); + io::FileOutputStream out(dest); + + in.streamTo(out); + + in.close(); + out.close(); + + } +}; + +int main(int argc, char **argv) +{ + try + { + + if (argc != 3) + throw except::Error( + Ctxt( + FmtX( + "Usage: %s ", + argv[0]))); + + Copy::run(argv[1], argv[2]); + } + catch (except::Throwable& e) + { + cout << e.toString() << endl; + } + +} diff --git a/modules/c++/io/tests/ioTest5.cpp b/modules/c++/io/tests/ioTest5.cpp new file mode 100644 index 000000000..87c13de7e --- /dev/null +++ b/modules/c++/io/tests/ioTest5.cpp @@ -0,0 +1,34 @@ +/* ========================================================================= + * This file is part of io-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * io-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include +#include +#include +#include + +using namespace std; + +int main() +{ + return 0; +} + diff --git a/modules/c++/io/tests/mmByteStreamTest.cpp b/modules/c++/io/tests/mmByteStreamTest.cpp new file mode 100644 index 000000000..cd6b5b587 --- /dev/null +++ b/modules/c++/io/tests/mmByteStreamTest.cpp @@ -0,0 +1,45 @@ +/* ========================================================================= + * This file is part of io-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * io-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include +using namespace io; + +int main(int argc, char *argv[]) +{ + if (argc != 3) + { + fprintf(stderr, "Usage: %s \n", argv[0]); + return -1; + } + + MMapInputStream iStream(argv[1]); + FileOutputStream oStream(argv[2]); + ByteStream bStream; + + iStream.streamTo(bStream); + bStream.streamTo(oStream); + + iStream.close(); + oStream.close(); + + return 0; +} diff --git a/modules/c++/io/tests/seekTest1.cpp b/modules/c++/io/tests/seekTest1.cpp new file mode 100644 index 000000000..c72b02b21 --- /dev/null +++ b/modules/c++/io/tests/seekTest1.cpp @@ -0,0 +1,125 @@ +/* ========================================================================= + * This file is part of io-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * io-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include + +const int LENGTH_STR = 26; + + +void testSeekCurrent(io::ByteStream& bs) +{ + char buffer[ LENGTH_STR + 1 ]; + buffer[ LENGTH_STR ] = 0; + // Simple scan through.... + int readVal = 0; + bs.seek(0, io::ByteStream::START); + + + + for (int i = 0; readVal != io::ByteStream::IS_END ; i++) + { + bs.seek(0, io::ByteStream::CURRENT); + readVal = bs.read(&buffer[i], 1); + std::cout << i << std::endl; + std::cout << readVal << std::endl; + } + + std::cout << "'" << buffer << "'" << std::endl; + +} + +int main() +{ + + try + { + + const std::string str = "abcdefghijklmnopqrstuvwxyz"; + std::cout << "Operating on string: '" << str << "'" << std::endl; + + io::ByteStream bs; + bs.write(str.c_str(), str.length()); + +// testSeekCurrent(bs); + char buffer[ LENGTH_STR + 1 ]; + buffer[ LENGTH_STR ] = 0; + // Simple scan through.... + int readVal = 0; + bs.seek(0, io::ByteStream::START); + + for (int i = 0; readVal != io::ByteStream::IS_END ; i++) + { + bs.seek(0, io::ByteStream::CURRENT); + readVal = bs.read(&buffer[i], 1); + } + + std::cout << "'" << buffer << "'" << std::endl; + + io::FileOutputStream fos("anything.txt"); + fos.write(buffer, LENGTH_STR); + fos.close(); + + + memset(buffer, 0, LENGTH_STR + 1); + + io::FileInputStream fis("anything.txt"); + int avail = (int)fis.available(); + fis.seek(0, io::FileInputStream::END); + readVal = 0; + + //std::cout << avail << std::endl; + for (int i = 0; i != avail ; i++) + { + fis.seek(-1, io::FileInputStream::CURRENT); + fis.read(&buffer[i], 1); + fis.seek(-1, io::FileInputStream::CURRENT); + + } + std::cout << "'" << buffer << "'" << std::endl; + io::ByteStream bwd; + bwd.write(buffer, LENGTH_STR); + avail = bwd.available(); + if ( avail != LENGTH_STR ) + throw except::Exception(Ctxt("Huh??")); + + + memset(buffer, 0, LENGTH_STR + 1); + + for (int i = avail; i > 0; --i) + { + int d = avail - i; + bwd.seek(i - 1, io::ByteStream::START); + bwd.read(&buffer[d], 1); + //std::cout << "At: " << d << ": " << buffer[d] << std::endl; + } + + std::cout << "'" << buffer << "'" << std::endl; + + return 0; + } + catch (except::Exception& ex) + { + std::cout << "Caught ex: " << ex.getTrace() << std::endl; + exit(EXIT_FAILURE); + } + +} diff --git a/modules/c++/io/tests/serializeTest1.cpp b/modules/c++/io/tests/serializeTest1.cpp new file mode 100644 index 000000000..7fe84247a --- /dev/null +++ b/modules/c++/io/tests/serializeTest1.cpp @@ -0,0 +1,148 @@ +/* ========================================================================= + * This file is part of io-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * io-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#include +#include +#include + +using namespace sys; +using namespace io; +using namespace except; +using namespace std; + +#define DEBUG_A true + +class A : public Serializable +{ +public: + A() + { + dbg.set(new FileOutputStream("dbg.out"), DEBUG_A); + + vec[0] = 0.0; + vec[1] = 0.0; + vec[2] = 0.0; + } + virtual ~A() {} + virtual void serialize(OutputStream& os) + { + os.writeln("Class A"); + os.writeln(FmtX("%f", vec[0])); + os.writeln(FmtX("%f", vec[1])); + os.writeln(FmtX("%f", vec[2])); + + } + virtual void deserialize(InputStream& is) + { + string classType = fillString(is); + string vec_0 = fillString(is); + string vec_1 = fillString(is); + string vec_2 = fillString(is); + + assert(classType == "Class A"); + dbg.writeln(FmtX("vec[0] = %s", vec_0.c_str())); + dbg.writeln(FmtX("vec[1] = %s", vec_1.c_str())); + dbg.writeln(FmtX("vec[2] = %s", vec_2.c_str())); + + vec[0] = str::toType(vec_0); + vec[1] = str::toType(vec_1); + vec[2] = str::toType(vec_2); + + } + std::string fillString(io::InputStream &is) + { + std::string toFill; + sys::byte b[1]; + while (true) + { + if (is.read(b, 1) == InputStream::IS_EOF) + throw IOException(Ctxt("Source corrupt") ); + + else if (b[0] == '\n') + { + return toFill; + } + else if (b[0] == '\r') + { + cout << "Warning: detected CR, ignoring" << endl; + } + else + { + toFill.append((const char*)b, 1); + } + } + + } + void setVector(float* f3v) + { + memcpy(vec, f3v, sizeof(float) * 3); + } + void getVector(float* f3v) + { + memcpy(f3v, vec, sizeof(float) * 3); + } + + bool operator==(const A& a) const + { + return (a.vec[0] == vec[0] && + a.vec[1] == vec[1] && + a.vec[2] == vec[2]); + } +protected: + DbgStream dbg; + float vec[3]; +}; + +int main(int argc, char **argv) +{ + StandardOutStream out; + A a; + a.serialize(out); + float f3v[3]; + f3v[0] = -2.0; + f3v[1] = 1.2; + f3v[2] = 8.6; + a.setVector(f3v); + + FileOutputStream fos("A.save"); + a.serialize(fos); + fos.close(); + + A a2; + FileInputStream fis("A.save"); + a2.deserialize(fis); + fis.close(); + + if (a == a2) + { + cout << "Successfully copied object a2 through object a via \"A.save\"" << endl; + a2.serialize(out); + } + else + { + cout << "Serialization process failed" << endl; + a2.serialize(out); + } + +} + diff --git a/modules/c++/io/tests/stringStreamTest1.cpp b/modules/c++/io/tests/stringStreamTest1.cpp new file mode 100644 index 000000000..799cab42b --- /dev/null +++ b/modules/c++/io/tests/stringStreamTest1.cpp @@ -0,0 +1,59 @@ +/* ========================================================================= + * This file is part of io-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * io-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include +#include +using namespace except; +using namespace io; +using namespace std; + +int main(int argc, char *argv[]) +{ + if (argc != 3) + { + fprintf(stderr, "Usage: %s \n", argv[0]); + return -1; + } + + try + { + FileInputStream iStream(argv[1]); + FileOutputStream oStream(argv[2]); + StringStream sStream; + + iStream.streamTo(sStream); + sStream.streamTo(oStream); + + iStream.close(); + oStream.close(); + } + catch (Throwable& t) + { + cerr << "Caught throwable: " << t.toString() << endl; + } + + catch (...) + { + cerr << "Caught unknown exception" << endl; + } + return 0; +} diff --git a/modules/c++/io/tests/stringStreamTest2.cpp b/modules/c++/io/tests/stringStreamTest2.cpp new file mode 100644 index 000000000..e6c634797 --- /dev/null +++ b/modules/c++/io/tests/stringStreamTest2.cpp @@ -0,0 +1,64 @@ +/* ========================================================================= + * This file is part of io-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * io-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include +#include +#include + +using namespace io; +using namespace except; +using namespace std; + +int main(int argc, char *argv[]) +{ + try + { + + std::string input("abcdefghijklmnopqrstuvwxyz"); + char buffer[32]; + memset(buffer, 0, 32); + StringStream sStream; + + sStream.write((const sys::byte*) input.c_str(), 5); + sStream.read((sys::byte*) buffer, 3); + cout << buffer << endl; + + memset(buffer, 0, 32); + sStream.write((const sys::byte*) input.c_str(), 10); + sStream.read((sys::byte*) buffer, 11); + cout << buffer << endl; + + memset(buffer, 0, 32); + sStream.read((sys::byte*) buffer, 100); + cout << buffer << endl; + + } + catch (Throwable& t) + { + cerr << "Caught throwable: " << t.toString() << endl; + } + catch (...) + { + cerr << "Caught unknown exception" << endl; + } + return 0; +} diff --git a/modules/c++/io/unittests/test_streams.cpp b/modules/c++/io/unittests/test_streams.cpp new file mode 100644 index 000000000..66252dad1 --- /dev/null +++ b/modules/c++/io/unittests/test_streams.cpp @@ -0,0 +1,164 @@ +/* ========================================================================= + * This file is part of io-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * io-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include +#include "TestCase.h" + +TEST_CASE(testByteStream) +{ + io::ByteStream stream; + stream.writeln("test"); + stream.seek(0, io::Seekable::START); + TEST_ASSERT_EQ(stream.available(), 5); + stream.reset(); + TEST_ASSERT_EQ(stream.available(), 0); + stream.write("test"); + TEST_ASSERT_EQ(stream.available(), 4); + sys::byte buf[255]; + stream.read(buf, 4); + buf[4] = 0; + TEST_ASSERT_EQ(std::string(buf), "test"); +} + +TEST_CASE(testProxyOutputStream) +{ + io::ByteStream stream; + io::ProxyOutputStream proxy(&stream); + proxy.write("test1"); + sys::byte buf[255]; + stream.read(buf, 5); + buf[5] = 0; + TEST_ASSERT_EQ(std::string(buf), "test1"); +} + +TEST_CASE(testCountingOutputStream) +{ + io::ByteStream stream; + io::CountingOutputStream counter(&stream); + counter.write("test1"); + TEST_ASSERT_EQ(counter.getCount(), 5); +} + +void cleanupFiles(std::string base) +{ + // cleanup + sys::OS os; + for (size_t i = 0;; ++i) + { + std::ostringstream oss; + oss << base << "." << (i + 1); + std::string fname(oss.str()); + if (os.isFile(fname)) + os.remove(fname); + else + break; + } + if (os.isFile(base)) + os.remove(base); +} + +TEST_CASE(testRotate) +{ + std::string outFile = "test_rotate.txt"; + size_t maxFiles = 5; + + cleanupFiles( outFile); + + sys::OS os; + io::RotatingFileOutputStream out(outFile, 10, maxFiles); + out.write("0123456789"); + TEST_ASSERT(os.exists(outFile)); + TEST_ASSERT_FALSE(os.isFile(outFile + ".1")); + + out.write("1"); + TEST_ASSERT(os.isFile(outFile + ".1")); + TEST_ASSERT_EQ(out.getCount(), 1); + + for(size_t i = 0; i < maxFiles - 1; ++i) + { + std::string fname = outFile + "." + str::toString(i + 1); + std::string next = outFile + "." + str::toString(i + 2); + + TEST_ASSERT(os.isFile(fname)); + TEST_ASSERT_FALSE(os.isFile(next)); + + out.write("0123456789"); + TEST_ASSERT(os.isFile(next)); + } + + cleanupFiles( outFile); +} + +TEST_CASE(testNeverRotate) +{ + std::string outFile = "test_rotate.txt"; + cleanupFiles( outFile); + + sys::OS os; + io::RotatingFileOutputStream out(outFile); + for(size_t i = 0; i < 1024; ++i) + out.write("0"); + TEST_ASSERT(os.exists(outFile)); + TEST_ASSERT_FALSE(os.isFile(outFile + ".1")); + TEST_ASSERT_EQ(out.getCount(), 1024); + cleanupFiles( outFile); +} + +TEST_CASE(testRotateReset) +{ + std::string outFile = "test_rotate.txt"; + cleanupFiles( outFile); + + sys::OS os; + io::RotatingFileOutputStream out(outFile, 10); + out.write("01234567890"); + TEST_ASSERT(os.exists(outFile)); + TEST_ASSERT_FALSE(os.isFile(outFile + ".1")); + TEST_ASSERT_EQ(out.getCount(), 11); + + out.write("0"); + TEST_ASSERT(os.exists(outFile)); + TEST_ASSERT_FALSE(os.isFile(outFile + ".1")); + TEST_ASSERT_EQ(out.getCount(), 1); + + out.close(); + try + { + out.write("0"); + TEST_FAIL("Stream is closed; should throw."); + } + catch(except::Exception& ex) + { + } + + cleanupFiles( outFile); +} + +int main(int argc, char* argv[]) +{ + TEST_CHECK( testByteStream); + TEST_CHECK( testProxyOutputStream); + TEST_CHECK( testCountingOutputStream); + TEST_CHECK( testRotate); + TEST_CHECK( testNeverRotate); + TEST_CHECK( testRotateReset); +} diff --git a/modules/c++/io/wscript b/modules/c++/io/wscript new file mode 100644 index 000000000..0fcc91816 --- /dev/null +++ b/modules/c++/io/wscript @@ -0,0 +1,11 @@ +NAME = 'io' +MAINTAINER = 'jmrandol@users.sourceforge.net' +VERSION = '1.0' +MODULE_DEPS = 'sys mem' +SOURCE_FILTER = 'MMapInputStream.cpp' +TEST_FILTER = 'mmByteStreamTest.cpp' + +options = configure = distclean = lambda p: None + +def build(bld): + bld.module(**globals()) diff --git a/modules/c++/logging/include/import/logging.h b/modules/c++/logging/include/import/logging.h new file mode 100644 index 000000000..3f12d62f5 --- /dev/null +++ b/modules/c++/logging/include/import/logging.h @@ -0,0 +1,45 @@ +/* ========================================================================= + * This file is part of logging-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * logging-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __IMPORT_LOGGING_H__ +#define __IMPORT_LOGGING_H__ + +#include "logging/DefaultLogger.h" +#include "logging/Enums.h" +#include "logging/FileHandler.h" +#include "logging/Filter.h" +#include "logging/Filterer.h" +#include "logging/Formatter.h" +#include "logging/Handler.h" +#include "logging/Logger.h" +#include "logging/LoggerFactory.h" +#include "logging/LogRecord.h" +#include "logging/MemoryHandler.h" +#include "logging/NullLogger.h" +#include "logging/RotatingFileHandler.h" +#include "logging/Setup.h" +#include "logging/StandardFormatter.h" +#include "logging/StreamHandler.h" +#include "logging/XMLFormatter.h" +#include "logging/ExceptionLogger.h" + +#endif diff --git a/modules/c++/logging/include/logging/DefaultLogger.h b/modules/c++/logging/include/logging/DefaultLogger.h new file mode 100644 index 000000000..6bc8f245e --- /dev/null +++ b/modules/c++/logging/include/logging/DefaultLogger.h @@ -0,0 +1,64 @@ +/* ========================================================================= + * This file is part of logging-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * logging-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +/////////////////////////////////////////////////////////// +// DefaultLogger.h +/////////////////////////////////////////////////////////// + +#ifndef __LOGGING_DEFAULT_LOGGER_H__ +#define __LOGGING_DEFAULT_LOGGER_H__ + +#include "logging/Logger.h" +#include "logging/StreamHandler.h" + +namespace logging +{ + +/*! + * \class DefaultLogger + * + * \brief DefaultLogger extends the Logger class by providing a default Handler + * which logs all messages to a StandardStream. This can of course be overridden. + */ +class DefaultLogger : public Logger +{ +protected: + Handler* mDefaultHandler; + + static LogLevel defaultLogLevel; + +public: + DefaultLogger(std::string name = ""); + + virtual ~DefaultLogger(); + + //! Returns the default Handler. You can modify, but do not destroy. + virtual Handler* getDefaultHandler() + { + return mDefaultHandler; + } + + static void setDefaultLogLevel(LogLevel logLevel); +}; + +} +#endif diff --git a/modules/c++/logging/include/logging/Enums.h b/modules/c++/logging/include/logging/Enums.h new file mode 100644 index 000000000..243c9720e --- /dev/null +++ b/modules/c++/logging/include/logging/Enums.h @@ -0,0 +1,182 @@ +/* ========================================================================= + * This file is part of logging-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * logging-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __LOGGING_ENUMS_H__ +#define __LOGGING_ENUMS_H__ + +#include +#include +#include + +// ----------------------------------------------------------------------------- +// This file is auto-generated - please do NOT edit directly +// ----------------------------------------------------------------------------- + +namespace logging +{ + + +/*! + * \struct LogLevel + * + * Enumeration used to represent LogLevels + */ +struct LogLevel +{ + //! The enumerations allowed + enum + { + LOG_NOTSET = 0, + LOG_DEBUG = 1, + LOG_INFO = 2, + LOG_WARNING = 3, + LOG_ERROR = 4, + LOG_CRITICAL = 5 + }; + + //! Default constructor + LogLevel(){ value = LOG_NOTSET; } + + //! string constructor + LogLevel(std::string s) + { + if (s == "LOG_NOTSET") + value = LOG_NOTSET; + else if (s == "NOTSET") + value = LOG_NOTSET; + else if (s == "LOG_DEBUG") + value = LOG_DEBUG; + else if (s == "DEBUG") + value = LOG_DEBUG; + else if (s == "LOG_INFO") + value = LOG_INFO; + else if (s == "INFO") + value = LOG_INFO; + else if (s == "LOG_WARNING") + value = LOG_WARNING; + else if (s == "WARNING") + value = LOG_WARNING; + else if (s == "LOG_WARN") + value = LOG_WARNING; + else if (s == "WARN") + value = LOG_WARNING; + else if (s == "LOG_ERROR") + value = LOG_ERROR; + else if (s == "ERROR") + value = LOG_ERROR; + else if (s == "LOG_CRITICAL") + value = LOG_CRITICAL; + else if (s == "CRITICAL") + value = LOG_CRITICAL; + else if (s == "LOG_SEVERE") + value = LOG_CRITICAL; + else if (s == "SEVERE") + value = LOG_CRITICAL; + else + throw except::InvalidFormatException(Ctxt(FmtX("Invalid enum value: %s", s.c_str()))); + } + + //! int constructor + LogLevel(int i) + { + switch(i) + { + case 0: + value = LOG_NOTSET; + break; + case 1: + value = LOG_DEBUG; + break; + case 2: + value = LOG_INFO; + break; + case 3: + value = LOG_WARNING; + break; + case 4: + value = LOG_ERROR; + break; + case 5: + value = LOG_CRITICAL; + break; + default: + throw except::InvalidFormatException(Ctxt(FmtX("Invalid enum value: %d", i))); + } + } + + //! destructor + ~LogLevel(){} + + //! Returns string representation of the value + std::string toString() const + { + switch(value) + { + case 0: + return std::string("NOTSET"); + case 1: + return std::string("DEBUG"); + case 2: + return std::string("INFO"); + case 3: + return std::string("WARNING"); + case 4: + return std::string("ERROR"); + case 5: + return std::string("CRITICAL"); + default: + throw except::InvalidFormatException(Ctxt(FmtX("Invalid enum value: %d", value))); + } + } + + //! assignment operator + LogLevel& operator=(const LogLevel& o) + { + if (&o != this) + { + value = o.value; + } + return *this; + } + + bool operator==(const LogLevel& o) const { return value == o.value; } + bool operator!=(const LogLevel& o) const { return value != o.value; } + bool operator==(const int& o) const { return value == o; } + bool operator!=(const int& o) const { return value != o; } + LogLevel& operator=(const int& o) { value = o; return *this; } + bool operator<(const LogLevel& o) const { return value < o.value; } + bool operator>(const LogLevel& o) const { return value > o.value; } + bool operator<=(const LogLevel& o) const { return value <= o.value; } + bool operator>=(const LogLevel& o) const { return value >= o.value; } + operator int() const { return value; } + operator std::string() const { return toString(); } + + int value; + +}; + +// code auto-generated 2011-03-15 13:25:08.574563 + +} + +#endif + diff --git a/modules/c++/logging/include/logging/ExceptionLogger.h b/modules/c++/logging/include/logging/ExceptionLogger.h new file mode 100644 index 000000000..be37b2b57 --- /dev/null +++ b/modules/c++/logging/include/logging/ExceptionLogger.h @@ -0,0 +1,75 @@ +/* ========================================================================= + * This file is part of logging-c++ + * ========================================================================= + * + * (C) Copyright 2013, General Dynamics - Advanced Information Systems + * + * logging-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +/////////////////////////////////////////////////////////// +// ExceptionLogger.h +/////////////////////////////////////////////////////////// + +#ifndef __LOGGING_EXCEPTION_LOGGER_H__ +#define __LOGGING_EXCEPTION_LOGGER_H__ + +#include "logging/Logger.h" +#include "logging/StreamHandler.h" +#include +#include + +namespace logging +{ + +/*! + * \class ExceptionLogger + * + * \brief ExceptionLogger owns a Logger and logs exceptions passed to it. + */ +class ExceptionLogger +{ +protected: + sys::Mutex mLock; + + Logger* mLogger; + + bool mHasLogged; + +public: + ExceptionLogger(Logger* logger) : mLogger(logger), mHasLogged(false) + {} + + virtual ~ExceptionLogger() {} + + //! Tells whether it has logged at least one exception + bool hasLogged() + { + mt::CriticalSection crit(&mLock); + return mHasLogged; + } + + //! Log the exception/throwable + void log(const except::Throwable& t, LogLevel logLevel) + { + mt::CriticalSection crit(&mLock); + mLogger->log(logLevel, t); + mHasLogged = true; + } +}; + +} +#endif diff --git a/modules/c++/logging/include/logging/FileHandler.h b/modules/c++/logging/include/logging/FileHandler.h new file mode 100644 index 000000000..255ed13a9 --- /dev/null +++ b/modules/c++/logging/include/logging/FileHandler.h @@ -0,0 +1,59 @@ +/* ========================================================================= + * This file is part of logging-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * logging-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +/////////////////////////////////////////////////////////// +// FileHandler.h +/////////////////////////////////////////////////////////// + +#ifndef __LOGGING_FILE_HANDLER_H__ +#define __LOGGING_FILE_HANDLER_H__ + +#include +#include +#include "logging/LogRecord.h" +#include "logging/StreamHandler.h" +#include + +namespace logging +{ +/*! + * \class FileHandler + * \brief Emits LogRecords to a file on disk. + */ +class FileHandler : public StreamHandler +{ + +public: + FileHandler(const std::string& fname, LogLevel level = LogLevel::LOG_NOTSET, + int creationFlags = sys::File::CREATE | sys::File::TRUNCATE) : + StreamHandler(new io::FileOutputStream(fname, creationFlags), level) + { + // In case we are in append mode + ((io::FileOutputStream*) mStream.get())->seek(0, io::Seekable::END); + } + virtual ~FileHandler() + { + } + +}; +} +#endif diff --git a/modules/c++/logging/include/logging/Filter.h b/modules/c++/logging/include/logging/Filter.h new file mode 100644 index 000000000..6557e445d --- /dev/null +++ b/modules/c++/logging/include/logging/Filter.h @@ -0,0 +1,55 @@ +/* ========================================================================= + * This file is part of logging-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * logging-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +/////////////////////////////////////////////////////////// +// Filter.h +/////////////////////////////////////////////////////////// + +#ifndef __LOGGING_FILTER_H__ +#define __LOGGING_FILTER_H__ + +#include +#include "logging/LogRecord.h" + +namespace logging +{ + +/*! + * \class Filter + * + * \brief Filter instances are used to perform arbitrary filtering of LogRecords. + */ +class Filter +{ +public: + Filter(std::string name = "") : mName(name){} + virtual ~Filter(){} + + bool filter(const LogRecord* record) const; + std::string getName() const { return mName; } + +protected: + std::string mName; +}; + +} +#endif diff --git a/modules/c++/logging/include/logging/Filterer.h b/modules/c++/logging/include/logging/Filterer.h new file mode 100644 index 000000000..32ee8c408 --- /dev/null +++ b/modules/c++/logging/include/logging/Filterer.h @@ -0,0 +1,67 @@ +/* ========================================================================= + * This file is part of logging-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * logging-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +/////////////////////////////////////////////////////////// +// Filterer.h +/////////////////////////////////////////////////////////// + +#ifndef __LOGGING_FILTERER_H__ +#define __LOGGING_FILTERER_H__ + +#include +#include +#include "logging/Filter.h" +#include "logging/LogRecord.h" + +namespace logging +{ + +/*! + * \class Filterer + * + * A base class for loggers and handlers which allows them to share + * common code. + */ +class Filterer +{ +public: + Filterer(){} + virtual ~Filterer(){} + + /*! + * Adds a Filter to the managed map of Filters. We do NOT take control of + * the pointer + */ + void addFilter(Filter* filter); + + bool filter(const LogRecord* record) const; + + //! Removes the specified Filter + void removeFilter(Filter* filter); + +protected: + std::map filters; + +}; + +} +#endif diff --git a/modules/c++/logging/include/logging/Formatter.h b/modules/c++/logging/include/logging/Formatter.h new file mode 100644 index 000000000..85dfcd5c1 --- /dev/null +++ b/modules/c++/logging/include/logging/Formatter.h @@ -0,0 +1,88 @@ +/* ========================================================================= + * This file is part of logging-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * logging-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +/////////////////////////////////////////////////////////// +// Formatter.h +/////////////////////////////////////////////////////////// + +#ifndef __LOGGING_FORMATTER_H__ +#define __LOGGING_FORMATTER_H__ + +#include +#include "logging/LogRecord.h" +#include "import/io.h" + + +namespace logging +{ + +/*! + * \class Formatter + * \brief This class is the interface for deriving formatters. + */ +class Formatter +{ +public: + + + Formatter() : mFmt(""), + mPrologue(""), + mEpilogue("") + { + } + + Formatter(const std::string& fmt, + const std::string& prologue = "", + const std::string& epilogue = "") : + mFmt(fmt), + mPrologue(prologue), + mEpilogue(epilogue) + { + } + + virtual ~Formatter() {} + + // returns string + virtual void format(const LogRecord* record, io::OutputStream& os) const = 0; + + virtual std::string getPrologue() const; + virtual std::string getEpilogue() const; + +protected: + + static const char THREAD_ID[]; + static const char LOG_NAME[]; + static const char LOG_LEVEL[]; + static const char TIMESTAMP[]; + static const char FILE_NAME[]; + static const char LINE_NUM[]; + static const char MESSAGE[]; + static const char FUNCTION[]; + + + const std::string mFmt; + const std::string mPrologue; + const std::string mEpilogue; +}; + +} +#endif diff --git a/modules/c++/logging/include/logging/Handler.h b/modules/c++/logging/include/logging/Handler.h new file mode 100644 index 000000000..7b8ebbd11 --- /dev/null +++ b/modules/c++/logging/include/logging/Handler.h @@ -0,0 +1,97 @@ +/* ========================================================================= + * This file is part of logging-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * logging-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +/////////////////////////////////////////////////////////// +// Handler.h +/////////////////////////////////////////////////////////// + +#ifndef __LOGGING_HANDLER_H__ +#define __LOGGING_HANDLER_H__ + +#include +#include "logging/LogRecord.h" +#include "logging/Formatter.h" +#include "logging/StandardFormatter.h" +#include "logging/Filterer.h" +#include +#include +#include + +namespace logging +{ + +/*! + * \class Handler + * + * The Handler class is abstract. Sub-classes handle LogRecord* objects, + * emitting the information in a user-defined manner. + */ +class Handler : public Filterer +{ +public: + /*! + * Construct a Handler at the specified LogLevel (LogLevel::LOG_NOTSET is default) + */ + Handler(LogLevel level = LogLevel::LOG_NOTSET); + virtual ~Handler() + { + } + + /*! + * Sets the Formatter to use when formatting LogRecords + * Not Threads Safe! + */ + virtual void setFormatter(Formatter* formatter); + + //! Sets the minimum LogLevel required to emit LogRecords + void setLevel(LogLevel level); + + //! Returns the LogLevel + LogLevel getLevel() const { return mLevel; } + + /*! + * Handles the LogRecord + * If the LogRecord meets the LogLevel criteria, it is formatted + * and emitted. + */ + virtual bool handle(const LogRecord* record); + + virtual void close(); + +protected: + + // for general string write + virtual void write(const std::string&) = 0; + + // for writing directly to stream, + // used for the bulk of the logging for speed + virtual void emitRecord(const LogRecord* record) = 0; + + + LogLevel mLevel; + sys::Mutex mHandlerLock; + Formatter* mFormatter; + StandardFormatter mDefaultFormatter; +}; + +} +#endif diff --git a/modules/c++/logging/include/logging/LogRecord.h b/modules/c++/logging/include/logging/LogRecord.h new file mode 100644 index 000000000..8eaf59c02 --- /dev/null +++ b/modules/c++/logging/include/logging/LogRecord.h @@ -0,0 +1,77 @@ +/* ========================================================================= + * This file is part of logging-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * logging-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +/////////////////////////////////////////////////////////// +// LogRecord.h +/////////////////////////////////////////////////////////// + +#ifndef __LOGGING_LOG_RECORD_H__ +#define __LOGGING_LOG_RECORD_H__ + +#include +#include "logging/Enums.h" + +namespace logging +{ + +/*! + * \class LogRecord + * + * \brief A LogRecord instance represents an event being logged. + * LogRecord instances are created every time something is logged. They + * contain all the information pertinent to the event being logged. The + * record also includes the timestamp when the record was created. + */ +class LogRecord +{ + +public: + LogRecord(std::string name, std::string msg, LogLevel level = LogLevel::LOG_NOTSET); + LogRecord(std::string name, std::string msg, LogLevel level, + std::string file, std::string function, int lineNum, std::string timestamp) : + mName(name), mMsg(msg), mLevel(level), mFile(file), mFunction(function), + mLineNum(lineNum), mTimestamp(timestamp){} + virtual ~LogRecord(){} + + LogLevel getLevel() const { return mLevel; } + std::string getLevelName() const; + + std::string getMessage() const { return mMsg; } + std::string getName() const { return mName; } + std::string getTimeStamp() const { return mTimestamp; } + std::string getFile() const { return mFile; } + std::string getFunction() const { return mFunction; } + int getLineNum() const { return mLineNum; } + + +private: + std::string mName; + std::string mMsg; + LogLevel mLevel; + std::string mFile; + std::string mFunction; + int mLineNum; + std::string mTimestamp; +}; + +} +#endif diff --git a/modules/c++/logging/include/logging/Logger.h b/modules/c++/logging/include/logging/Logger.h new file mode 100644 index 000000000..927a9de8c --- /dev/null +++ b/modules/c++/logging/include/logging/Logger.h @@ -0,0 +1,143 @@ +/* ========================================================================= + * This file is part of logging-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * logging-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +/////////////////////////////////////////////////////////// +// Logger.h +/////////////////////////////////////////////////////////// + +#ifndef __LOGGING_LOGGER_H__ +#define __LOGGING_LOGGER_H__ + +#include +#include +#include "logging/Filterer.h" +#include "logging/LogRecord.h" +#include "logging/Handler.h" +#include + +namespace logging +{ + +/*! + * \class Logger + * + * Instances of the Logger class represent a single logging channel. + * A Logger instance can log to several Handlers. + */ +class Logger : public Filterer +{ + +public: + /*! + * Constructs a Logger with an optional name + * \param name (optional) Name of the logger + */ + Logger(std::string name = "") : + mName(name) + { + } + virtual ~Logger(); + + //! Logs a message at the specified LogLevel + void log(LogLevel level, const std::string& msg); + + //! Logs an Exception Context at the specified LogLevel + void log(LogLevel level, const except::Context& ctxt); + + //! Logs a Throwable at the specified LogLevel + void log(LogLevel level, const except::Throwable& t); + + //! Logs a message at the DEBUG LogLevel + void debug(const std::string& msg); + //! Logs a message at the INFO LogLevel + void info(const std::string& msg); + //! Logs a message at the WARNING LogLevel + void warn(const std::string& msg); + //! Logs a message at the ERROR LogLevel + void error(const std::string& msg); + //! Logs a message at the CRITICAL LogLevel + void critical(const std::string& msg); + + //! Logs an Exception Context at the DEBUG LogLevel + void debug(const except::Context& ctxt); + //! Logs an Exception Context at the INFO LogLevel + void info(const except::Context& ctxt); + //! Logs an Exception Context at the WARNING LogLevel + void warn(const except::Context& ctxt); + //! Logs an Exception Context at the ERROR LogLevel + void error(const except::Context& ctxt); + //! Logs an Exception Context at the CRITICAL LogLevel + void critical(const except::Context& ctxt); + + //! Logs a Throwable at the DEBUG LogLevel + void debug(const except::Throwable& t); + //! Logs a Throwable at the INFO LogLevel + void info(const except::Throwable& t); + //! Logs a Throwable at the WARNING LogLevel + void warn(const except::Throwable& t); + //! Logs a Throwable at the ERROR LogLevel + void error(const except::Throwable& t); + //! Logs a Throwable at the CRITICAL LogLevel + void critical(const except::Throwable& t); + + /*! + * Adds a Hander to the list of Handlers this Logger delegates to. + * This Logger does not own the passed-in Handler. + */ + void addHandler(Handler* handler, bool own = false); + + /*! + * Removes the specified Handler from the list of Handlers. + */ + void removeHandler(Handler* handler); + + /*! + * This sets the LogLevel for all of the Handlers for this Logger + */ + void setLevel(LogLevel level); + + //! Sets the name of the Logger + void setName(const std::string& name) + { + mName = name; + } + //! Returns the name of the Logger + std::string getName() const + { + return mName; + } + + //! Removes all handlers + void reset(); + +protected: + void handle(const LogRecord* record); + + typedef std::pair Handler_T; + typedef std::vector Handlers_T; + + std::string mName; + Handlers_T mHandlers; + +}; +} +#endif diff --git a/modules/c++/logging/include/logging/LoggerFactory.h b/modules/c++/logging/include/logging/LoggerFactory.h new file mode 100644 index 000000000..a41ed13db --- /dev/null +++ b/modules/c++/logging/include/logging/LoggerFactory.h @@ -0,0 +1,95 @@ +/////////////////////////////////////////////////////////// +// LoggerFactory.h +/////////////////////////////////////////////////////////// + +#ifndef __LOGGING_LOGGER_FACTORY_H__ +#define __LOGGING_LOGGER_FACTORY_H__ + +#include +#include +#include +#include "logging/DefaultLogger.h" + +namespace logging +{ + +/*! + * \class LoggerManager + * \brief The LoggerManager class maintains a static list of Loggers that can + * be accessed from any context of your application simply by calling the + * static getLogger() method. All Loggers are kept as pointers to heap memory, + * and will get destructed at exit. + */ +class LoggerManager +{ +private: + std::map mLoggerMap; //! map for storing Loggers + sys::Mutex mMutex; //! mutex used for locking the map + +public: + LoggerManager() {} + ~LoggerManager(); + + /*! + * Returns the Logger with the specified name. If a logger with the + * given name does not exist, a new Logger is created, loaded with the + * default values in the sytem. If the name is not supplied, the root logger + * is used by default. + */ + Logger* getLogger(std::string name = "root"); +}; + +/*! + * This is where all the magic happens. The LoggerFactory is a LoggerManager + * Singleton. Therefore, you can use a shared LoggerManager by using the + * LoggerFactory. + */ +typedef mt::Singleton LoggerFactory; + + +//below are some shortcuts at the namespace level +//this allows you to call logging::warn("foo") from anywhere +//and it will use the root logger that is managed by the factory singleton + +//! Logs a message at the DEBUG LogLevel to the 'root' logger +void debug(const std::string& msg); +//! Logs a message at the INFO LogLevel to the 'root' logger +void info(const std::string& msg); +//! Logs a message at the WARNING LogLevel to the 'root' logger +void warn(const std::string& msg); +//! Logs a message at the ERROR LogLevel to the 'root' logger +void error(const std::string& msg); +//! Logs a message at the CRITICAL LogLevel to the 'root' logger +void critical(const std::string& msg); + +//! Logs an Exception Context at the DEBUG LogLevel to the 'root' logger +void debug(const except::Context& ctxt); +//! Logs an Exception Context at the INFO LogLevel to the 'root' logger +void info(const except::Context& ctxt); +//! Logs an Exception Context at the WARNING LogLevel to the 'root' logger +void warn(const except::Context& ctxt); +//! Logs an Exception Context at the ERROR LogLevel to the 'root' logger +void error(const except::Context& ctxt); +//! Logs an Exception Context at the CRITICAL LogLevel to the 'root' logger +void critical(const except::Context& ctxt); + +//! Logs a Throwable at the DEBUG LogLevel to the 'root' logger +void debug(except::Throwable& t); +//! Logs a Throwable at the INFO LogLevel to the 'root' logger +void info(except::Throwable& t); +//! Logs a Throwable at the WARNING LogLevel to the 'root' logger +void warn(except::Throwable& t); +//! Logs a Throwable at the ERROR LogLevel to the 'root' logger +void error(except::Throwable& t); +//! Logs a Throwable at the CRITICAL LogLevel to the 'root' logger +void critical(except::Throwable& t); + +//! Sets the LogLevel for the default 'root' logger +//TODO deprecate this +void setLogLevel(LogLevel level); + +//! get a Logger of the given name +Logger* getLogger(std::string name = "root"); + +} +#endif diff --git a/modules/c++/logging/include/logging/MemoryHandler.h b/modules/c++/logging/include/logging/MemoryHandler.h new file mode 100644 index 000000000..a2e29b774 --- /dev/null +++ b/modules/c++/logging/include/logging/MemoryHandler.h @@ -0,0 +1,62 @@ +/* ========================================================================= + * This file is part of logging-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * logging-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +/////////////////////////////////////////////////////////// +// MemoryHandler.h +/////////////////////////////////////////////////////////// + +#ifndef __LOGGING_MEMORY_HANDLER_H__ +#define __LOGGING_MEMORY_HANDLER_H__ + +#include +#include +#include +#include "logging/LogRecord.h" +#include "logging/Handler.h" + +namespace logging +{ +/*! + * \class MemoryHandler + * \brief Emits LogRecords to memory. + */ +class MemoryHandler : public Handler +{ + +public: + MemoryHandler(LogLevel level = LogLevel::LOG_NOTSET); + + const std::vector& + getLogs(LogLevel level = LogLevel::LOG_NOTSET) const; + +protected: + virtual void write(const std::string& str); + + virtual void emitRecord(const LogRecord* record); + +private: + typedef std::map > LogMap; + LogMap mLogMap; +}; + +} +#endif diff --git a/modules/c++/logging/include/logging/NullLogger.h b/modules/c++/logging/include/logging/NullLogger.h new file mode 100644 index 000000000..a13b682f8 --- /dev/null +++ b/modules/c++/logging/include/logging/NullLogger.h @@ -0,0 +1,83 @@ +/* ========================================================================= + * This file is part of logging-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * logging-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +/////////////////////////////////////////////////////////// +// NullHandler.h +/////////////////////////////////////////////////////////// + +#ifndef __LOGGING_NULL_LOGGER_H__ +#define __LOGGING_NULL_LOGGER_H__ + +#include "logging/Logger.h" +#include "logging/Handler.h" + +namespace logging +{ + +/*! + * \class NullHandler + * \brief Ignores all records + */ +class NullHandler : public Handler +{ + +public: + NullHandler(LogLevel level = LogLevel::LOG_NOTSET) : + Handler(level) + { + } + ~NullHandler() + { + } + +protected: + + virtual void write(const std::string&) + { + // does nothing... + } + void emitRecord(const LogRecord* record) + { + // does nothing... + } +}; + +/** + * A Logger that doesn't actually log anything. It can be used in cases where + * a Logger is required but you don't want anything to log. + */ +class NullLogger : public Logger +{ +public: + NullLogger(const std::string& name = "") : + Logger(name) + { + addHandler(new NullHandler, true); + } + + ~NullLogger() + { + } +}; + +} +#endif diff --git a/modules/c++/logging/include/logging/RotatingFileHandler.h b/modules/c++/logging/include/logging/RotatingFileHandler.h new file mode 100644 index 000000000..4f26028d4 --- /dev/null +++ b/modules/c++/logging/include/logging/RotatingFileHandler.h @@ -0,0 +1,66 @@ +/* ========================================================================= + * This file is part of logging-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * logging-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +/////////////////////////////////////////////////////////// +// RotatingFileHandler.h +/////////////////////////////////////////////////////////// + +#ifndef __LOGGING_ROTATING_FILE_HANDLER_H__ +#define __LOGGING_ROTATING_FILE_HANDLER_H__ + +#include +#include +#include "logging/LogRecord.h" +#include "logging/StreamHandler.h" +#include +#include + +namespace logging +{ + +/*! + * \class RotatingFileHandler + * + * RotatingFileHandler is a special Handler that emits logging to a file that + * rotates once it reaches a certain maximum size. When the file rotates, it + * will be renamed, thus creating a backup. For example, let's assume we are + * logging to a file named 'error.log'. When the file rotates, it will be + * renamed to 'error.log.1', and all future logs will be logged to error.log. + * This is useful if you would like to keep backups of logs. + */ +class RotatingFileHandler : public StreamHandler +{ + +public: + /*! + * \param fname The file to log to + * \param maxBytes The max file size + * \param backupCount The max number of backups + * \param level The minimum LogLevel + */ + RotatingFileHandler(const std::string& fname, long maxBytes = 0, + int backupCount = 0, LogLevel level = LogLevel::LOG_NOTSET); + + virtual ~RotatingFileHandler(); +}; +} +#endif diff --git a/modules/c++/logging/include/logging/Setup.h b/modules/c++/logging/include/logging/Setup.h new file mode 100644 index 000000000..dfb3400bb --- /dev/null +++ b/modules/c++/logging/include/logging/Setup.h @@ -0,0 +1,58 @@ +/* ========================================================================= + * This file is part of logging-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * logging-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __LOGGING_SETUP_H__ +#define __LOGGING_SETUP_H__ + +#include +#include + +#include "logging/Logger.h" + +namespace logging +{ + +/*! + * \fn setupLogger + * + * This is a simple utility for logging. Creation of the logger is + * non-trivial in nature, so this helpful utility reduces the setup + * to a few parameters. + * + * \param program - name of the program doing the logging + * \param logLevel - level of logging (debug|warning|info|error|critical) + * \param logFile - location where to log (default: console logs to std::cout) + * \param logFormat- format of the log (default: [%p] (%d) %m) + * \param logCount - number of rotating logs to keep (default: 0 no rotation) + * \param logBytes - number of bytes per rotating log (default: 0 no rotation) + */ +std::auto_ptr setupLogger( + const std::string& program, + const std::string& logLevel = "warning", + const std::string& logFile = "console", + const std::string& logFormat = "[%p] (%d) %m", + size_t logCount = 0, + size_t logBytes = 0); + +} + +#endif diff --git a/modules/c++/logging/include/logging/StandardFormatter.h b/modules/c++/logging/include/logging/StandardFormatter.h new file mode 100644 index 000000000..123bdc690 --- /dev/null +++ b/modules/c++/logging/include/logging/StandardFormatter.h @@ -0,0 +1,72 @@ +/* ========================================================================= + * This file is part of logging-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * logging-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +/////////////////////////////////////////////////////////// +// StandardFormatter.h +/////////////////////////////////////////////////////////// + +#ifndef __LOGGING_STANDARD_FORMATTER_H__ +#define __LOGGING_STANDARD_FORMATTER_H__ + +#include +#include +#include "logging/Formatter.h" +#include "logging/LogRecord.h" + +namespace logging +{ + +/*! + * \class StandardFormatter + * \brief This class provides default formatting capabilities. The syntax + * for the format string maps to that which is used in log4j. + * + * c = Log Name + * p = Log Level + * d = Date/Time + * F = File name + * L = Line number + * M = Function + * m = Log message + * t = Thread id + * + * The default format looks like this: + * [%c] %p %d ==> %m + */ +class StandardFormatter : public Formatter +{ +public: + static const char DEFAULT_FORMAT[]; + + StandardFormatter() : Formatter(DEFAULT_FORMAT) {} + StandardFormatter(const std::string& fmt, + const std::string& prologue = "", + const std::string& epilogue = ""); + + virtual ~StandardFormatter() {} + + virtual void format(const LogRecord* record, io::OutputStream& os) const; + +}; + +} +#endif diff --git a/modules/c++/logging/include/logging/StreamHandler.h b/modules/c++/logging/include/logging/StreamHandler.h new file mode 100644 index 000000000..7792efdb3 --- /dev/null +++ b/modules/c++/logging/include/logging/StreamHandler.h @@ -0,0 +1,76 @@ +/* ========================================================================= + * This file is part of logging-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * logging-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +/////////////////////////////////////////////////////////// +// StreamHandler.h +/////////////////////////////////////////////////////////// + +#ifndef __LOGGING_STREAM_HANDLER_H__ +#define __LOGGING_STREAM_HANDLER_H__ + +#include +#include "logging/LogRecord.h" +#include "logging/Handler.h" +#include + +namespace logging +{ + +/*! + * \class StreamHandler + * \brief Emits LogRecords to an io::OutputStream + */ +class StreamHandler : public Handler +{ +public: + //! Constructs a StreamHandler that uses an io::StandardOutStream + StreamHandler(LogLevel level = LogLevel::LOG_NOTSET); + + //! Constructs a StreamHandler using the specified OutputStream + StreamHandler(io::OutputStream* stream, LogLevel level = LogLevel::LOG_NOTSET); + + virtual ~StreamHandler() + { + close(); + } + + //! adds the need to write epilogue before deleting formatter + // and then writing the prologue with the new formatter + virtual void setFormatter(Formatter* formatter); + + virtual void close(); + +protected: + + //! for general string write + virtual void write(const std::string&); + + //! for writing directly to stream, + // used for the bulk of the logging for speed + virtual void emitRecord(const LogRecord* record); + + + std::auto_ptr mStream; +}; + +} +#endif diff --git a/modules/c++/logging/include/logging/XMLFormatter.h b/modules/c++/logging/include/logging/XMLFormatter.h new file mode 100644 index 000000000..878544dfa --- /dev/null +++ b/modules/c++/logging/include/logging/XMLFormatter.h @@ -0,0 +1,74 @@ +/* ========================================================================= + * This file is part of logging + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * logging-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ +#ifndef __LOGGING_XML_FORMATTER_H__ +#define __LOGGING_XML_FORMATTER_H__ + +#include +#include +#include "logging/Formatter.h" +#include "logging/LogRecord.h" + +namespace logging +{ + +/*! + * \class XMLFormatter + * \brief This class converts the standard log format to XML. The syntax + * for the logger remains the same as the default Formatter, but separates + * the LogRecord into separate elements. + * + * c = Log Name + * p = Log Level + * d = Date/Time + * F = File name + * L = Line number + * M = Function + * m = Log message + * t = Thread id + * + * The default XML format looks like this: + * + * %F + * %m + * + * + */ +class XMLFormatter : public logging::Formatter +{ +public: + + static const char DEFAULT_FORMAT[]; + static const char XML_SAFE_CONVERSION[]; + + XMLFormatter(); + XMLFormatter(const std::string& fmt, + const std::string& prologue = "", + const std::string& epilogue = ""); + + virtual ~XMLFormatter(){} + + virtual void format(const logging::LogRecord* record, io::OutputStream& os) const; + +}; + +} +#endif diff --git a/modules/c++/logging/source/DefaultLogger.cpp b/modules/c++/logging/source/DefaultLogger.cpp new file mode 100644 index 000000000..bfe48440c --- /dev/null +++ b/modules/c++/logging/source/DefaultLogger.cpp @@ -0,0 +1,32 @@ +/////////////////////////////////////////////////////////// +// DefaultLogger.cpp +/////////////////////////////////////////////////////////// + +#include "logging/DefaultLogger.h" + + +logging::LogLevel logging::DefaultLogger::defaultLogLevel = logging::LogLevel::LOG_WARNING; + + +logging::DefaultLogger::DefaultLogger(std::string name) + : logging::Logger(name) +{ + //TODO might be able to share just one amongst all DefaultLoggers -- just a thought + mDefaultHandler = new logging::StreamHandler(defaultLogLevel); + this->addHandler(mDefaultHandler); +} + +logging::DefaultLogger::~DefaultLogger() +{ + if (mDefaultHandler) + { + this->removeHandler(mDefaultHandler); + delete mDefaultHandler; + } +} + + +void logging::DefaultLogger::setDefaultLogLevel(logging::LogLevel logLevel) +{ + logging::DefaultLogger::defaultLogLevel = logLevel; +} diff --git a/modules/c++/logging/source/Filter.cpp b/modules/c++/logging/source/Filter.cpp new file mode 100644 index 000000000..44b7010f0 --- /dev/null +++ b/modules/c++/logging/source/Filter.cpp @@ -0,0 +1,39 @@ +/* ========================================================================= + * This file is part of logging-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * logging-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +/////////////////////////////////////////////////////////// +// Filter.cpp +/////////////////////////////////////////////////////////// + +#include "logging/Filter.h" + + +bool logging::Filter::filter(const logging::LogRecord* record) const +{ + std::string recName = record->getName(); + if (mName.empty() || recName == mName) + return true; + else if (recName.find(mName, 0) != 0) + return false; + return recName.length() > mName.length() && recName[mName.length()] == '.'; +} + diff --git a/modules/c++/logging/source/Filterer.cpp b/modules/c++/logging/source/Filterer.cpp new file mode 100644 index 000000000..0dc599c09 --- /dev/null +++ b/modules/c++/logging/source/Filterer.cpp @@ -0,0 +1,54 @@ +/* ========================================================================= + * This file is part of logging-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * logging-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +/////////////////////////////////////////////////////////// +// Filterer.cpp +/////////////////////////////////////////////////////////// + +#include "logging/Filterer.h" + + +void logging::Filterer::addFilter(logging::Filter* filter) +{ + if (filters.find(filter->getName()) == filters.end()) + { + filters[filter->getName()] = filter; + } +} + +bool logging::Filterer::filter(const logging::LogRecord* record) const +{ + for (std::map::const_iterator p = filters.begin(); + p != filters.end(); ++p) + { + if (!p->second->filter(record)) + return false; + } + return true; +} + +void logging::Filterer::removeFilter(logging::Filter* filter) +{ + filters.erase(filter->getName()); + +} + diff --git a/modules/c++/logging/source/Formatter.cpp b/modules/c++/logging/source/Formatter.cpp new file mode 100644 index 000000000..35619c666 --- /dev/null +++ b/modules/c++/logging/source/Formatter.cpp @@ -0,0 +1,53 @@ +/* ========================================================================= + * This file is part of logging-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * logging-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +/////////////////////////////////////////////////////////// +// StandardFormatter.cpp +/////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include "logging/Formatter.h" + +const char logging::Formatter::THREAD_ID[] = "%t"; +const char logging::Formatter::LOG_NAME[] = "%c"; +const char logging::Formatter::LOG_LEVEL[] = "%p"; +const char logging::Formatter::TIMESTAMP[] = "%d"; +const char logging::Formatter::FILE_NAME[] = "%F"; +const char logging::Formatter::LINE_NUM[] = "%L"; +const char logging::Formatter::MESSAGE[] = "%m"; +const char logging::Formatter::FUNCTION[] = "%M"; + + +std::string logging::Formatter::getPrologue() const +{ + return (mPrologue.empty()) ? "" : mPrologue + "\n"; +} +std::string logging::Formatter::getEpilogue() const +{ + return (mEpilogue.empty()) ? "" : mEpilogue + "\n"; +} + + + diff --git a/modules/c++/logging/source/Handler.cpp b/modules/c++/logging/source/Handler.cpp new file mode 100644 index 000000000..e08e8452c --- /dev/null +++ b/modules/c++/logging/source/Handler.cpp @@ -0,0 +1,81 @@ +/* ========================================================================= + * This file is part of logging-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * logging-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +/////////////////////////////////////////////////////////// +// Handler.cpp +/////////////////////////////////////////////////////////// + +#include "logging/Handler.h" + + +logging::Handler::Handler(logging::LogLevel level) +{ + mLevel = level; + + // use standard formatter by default + mFormatter = &mDefaultFormatter; +} + +void logging::Handler::close() +{ + // delete if necessary + if (mFormatter != &mDefaultFormatter && + mFormatter != NULL) + delete mFormatter; +} + +void logging::Handler::setLevel(logging::LogLevel level) +{ + mLevel = level; +} + +bool logging::Handler::handle(const logging::LogRecord* record) +{ + bool rv = false; + if (filter(record)) + { + //acquire lock + mt::CriticalSection lock(&mHandlerLock); + try + { + emitRecord(record); + rv = true; + } + catch (except::Throwable & t) + { + //TODO do something here? + //std::cout << t.getTrace() << std::endl; + } + } + return rv; +} +void logging::Handler::setFormatter(logging::Formatter* formatter) +{ + //check if current formatter + if (mFormatter != formatter) + { + // delete old formatter + Handler::close(); + + mFormatter = formatter; + } +} diff --git a/modules/c++/logging/source/LogRecord.cpp b/modules/c++/logging/source/LogRecord.cpp new file mode 100644 index 000000000..ada032bab --- /dev/null +++ b/modules/c++/logging/source/LogRecord.cpp @@ -0,0 +1,38 @@ +/* ========================================================================= + * This file is part of logging-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * logging-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +/////////////////////////////////////////////////////////// +// LogRecord.cpp +/////////////////////////////////////////////////////////// + +#include "logging/LogRecord.h" +#include "sys/TimeStamp.h" + +logging::LogRecord::LogRecord(std::string name, std::string msg, logging::LogLevel level) + : mName(name), mMsg(msg), mLevel(level), mFile(""), mFunction(""), mLineNum(-1) +{ + mTimestamp = sys::TimeStamp(true).local(); +} + + +std::string logging::LogRecord::getLevelName() const { return mLevel.toString(); }; + diff --git a/modules/c++/logging/source/Logger.cpp b/modules/c++/logging/source/Logger.cpp new file mode 100644 index 000000000..8f72d7e8d --- /dev/null +++ b/modules/c++/logging/source/Logger.cpp @@ -0,0 +1,216 @@ +/* ========================================================================= + * This file is part of logging-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * logging-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +/////////////////////////////////////////////////////////// +// Logger.cpp +/////////////////////////////////////////////////////////// + +#include "logging/Logger.h" +#include + +logging::Logger::~Logger() +{ + reset(); +} + +void logging::Logger::log(logging::LogLevel level, const std::string& msg) +{ + logging::LogRecord *rec = new logging::LogRecord(mName, msg, level); + handle(rec); + delete rec; +} + +void logging::Logger::log(LogLevel level, const except::Context& ctxt) +{ + logging::LogRecord *rec = new logging::LogRecord(mName, ctxt.getMessage(), + level, ctxt.getFile(), + ctxt.getFunction(), + ctxt.getLine(), + ctxt.getTime()); + handle(rec); + delete rec; +} + +void logging::Logger::log(LogLevel level, const except::Throwable& t) +{ + std::deque savedContexts; + except::Trace trace = t.getTrace(); + const size_t size = trace.getSize(); + if (size > 0) + { + for (size_t ii = 0; ii < size; ++ii) + { + savedContexts.push_front(trace.getContext()); + trace.popContext(); + } + // Do this so we print the original context first + for (size_t ii = 0; ii < savedContexts.size(); ++ii) + { + log(level, savedContexts[ii]); + } + } + else + { + // Just log the message + log(level, t.getMessage()); + } +} + +void logging::Logger::debug(const std::string& msg) +{ + log(LogLevel::LOG_DEBUG, msg); +} + +void logging::Logger::info(const std::string& msg) +{ + log(LogLevel::LOG_INFO, msg); +} + +void logging::Logger::warn(const std::string& msg) +{ + log(LogLevel::LOG_WARNING, msg); +} + +void logging::Logger::error(const std::string& msg) +{ + log(LogLevel::LOG_ERROR, msg); +} + +void logging::Logger::critical(const std::string& msg) +{ + log(LogLevel::LOG_CRITICAL, msg); +} + + +void logging::Logger::debug(const except::Context& ctxt) +{ + log(LogLevel::LOG_DEBUG, ctxt); +} + +void logging::Logger::info(const except::Context& ctxt) +{ + log(LogLevel::LOG_INFO, ctxt); +} + +void logging::Logger::warn(const except::Context& ctxt) +{ + log(LogLevel::LOG_WARNING, ctxt); +} + +void logging::Logger::error(const except::Context& ctxt) +{ + log(LogLevel::LOG_ERROR, ctxt); +} + +void logging::Logger::critical(const except::Context& ctxt) +{ + log(LogLevel::LOG_CRITICAL, ctxt); +} + +void logging::Logger::debug(const except::Throwable& t) +{ + log(LogLevel::LOG_DEBUG, t); +} + +void logging::Logger::info(const except::Throwable& t) +{ + log(LogLevel::LOG_INFO, t); +} + +void logging::Logger::warn(const except::Throwable& t) +{ + log(LogLevel::LOG_WARNING, t); +} + +void logging::Logger::error(const except::Throwable& t) +{ + log(LogLevel::LOG_ERROR, t); +} + +void logging::Logger::critical(const except::Throwable& t) +{ + log(LogLevel::LOG_CRITICAL, t); +} + +void logging::Logger::handle(const logging::LogRecord* record) +{ + if (filter(record)) + { + for (Handlers_T::iterator p = mHandlers.begin(); p != mHandlers.end(); ++p) + { + //std::cout << (int)(*p)->getLevel() << std::endl; + //only handle if it is above/equal to threshold + if (p->first->getLevel() <= record->getLevel()) + p->first->handle(record); + } + } +} + +void logging::Logger::addHandler(logging::Handler* handler, bool own) +{ + //only add the handler if it isn't added already + bool found = false; + for (Handlers_T::iterator p = mHandlers.begin(); p != mHandlers.end() + && !found; ++p) + { + if (p->first == handler) + { + found = true; + p->second = own; + } + } + if (!found) + mHandlers.push_back(Handler_T(handler, own)); +} + +void logging::Logger::removeHandler(logging::Handler* handler) +{ + //find and remove, if it exists + for (Handlers_T::iterator p = mHandlers.begin(); p != mHandlers.end(); ++p) + { + if (p->first == handler) + { + mHandlers.erase(p); + break; + } + } +} + +void logging::Logger::setLevel(LogLevel level) +{ + for (Handlers_T::iterator p = mHandlers.begin(); p != mHandlers.end(); ++p) + { + //set the level + p->first->setLevel(level); + } +} + +void logging::Logger::reset() +{ + for (Handlers_T::iterator p = mHandlers.begin(); p + != mHandlers.end(); ++p) + { + if (p->second && p->first) + delete p->first; + } + mHandlers.clear(); +} diff --git a/modules/c++/logging/source/LoggerFactory.cpp b/modules/c++/logging/source/LoggerFactory.cpp new file mode 100644 index 000000000..54465fd68 --- /dev/null +++ b/modules/c++/logging/source/LoggerFactory.cpp @@ -0,0 +1,97 @@ +/* ========================================================================= + * This file is part of logging-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * logging-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +/////////////////////////////////////////////////////////// +// LoggerFactory.cpp +/////////////////////////////////////////////////////////// + +#include "logging/LoggerFactory.h" + + +logging::LoggerManager::~LoggerManager() +{ + for (std::map::iterator it = mLoggerMap.begin(); + it != mLoggerMap.end(); ++it) + { + if (it->second) + { + delete it->second; + } + } +} + +logging::Logger* logging::LoggerManager::getLogger(std::string name) +{ + mt::CriticalSection obtainLock(&mMutex); + if (mLoggerMap.find(name) == mLoggerMap.end()) + { + logging::Logger* logger = new logging::DefaultLogger(name); + mLoggerMap[name] = logger; + } + return mLoggerMap[name]; +} + + + + + +void logging::debug(const std::string& msg) +{ logging::LoggerFactory::getInstance().getLogger()->debug(msg); } +void logging::info(const std::string& msg) +{ logging::LoggerFactory::getInstance().getLogger()->info(msg); } +void logging::warn(const std::string& msg) +{ logging::LoggerFactory::getInstance().getLogger()->warn(msg); } +void logging::error(const std::string& msg) +{ logging::LoggerFactory::getInstance().getLogger()->error(msg); } +void logging::critical(const std::string& msg) +{ logging::LoggerFactory::getInstance().getLogger()->critical(msg); } +void logging::debug(const except::Context& ctxt) +{ logging::LoggerFactory::getInstance().getLogger()->debug(ctxt); } +void logging::info(const except::Context& ctxt) +{ logging::LoggerFactory::getInstance().getLogger()->info(ctxt); } +void logging::warn(const except::Context& ctxt) +{ logging::LoggerFactory::getInstance().getLogger()->warn(ctxt); } +void logging::error(const except::Context& ctxt) +{ logging::LoggerFactory::getInstance().getLogger()->error(ctxt); } +void logging::critical(const except::Context& ctxt) +{ logging::LoggerFactory::getInstance().getLogger()->critical(ctxt); } +void logging::debug(except::Throwable& t) +{ logging::LoggerFactory::getInstance().getLogger()->debug(t); } +void logging::info(except::Throwable& t) +{ logging::LoggerFactory::getInstance().getLogger()->info(t); } +void logging::warn(except::Throwable& t) +{ logging::LoggerFactory::getInstance().getLogger()->warn(t); } +void logging::error(except::Throwable& t) +{ logging::LoggerFactory::getInstance().getLogger()->error(t); } +void logging::critical(except::Throwable& t) +{ logging::LoggerFactory::getInstance().getLogger()->critical(t); } + +void logging::setLogLevel(logging::LogLevel level) +{ + //set the level of the root logger + logging::LoggerFactory::getInstance().getLogger()->setLevel(level); +} + +logging::Logger* logging::getLogger(std::string name) +{ + return logging::LoggerFactory::getInstance().getLogger(name); +} diff --git a/modules/c++/logging/source/MemoryHandler.cpp b/modules/c++/logging/source/MemoryHandler.cpp new file mode 100644 index 000000000..996e11fb5 --- /dev/null +++ b/modules/c++/logging/source/MemoryHandler.cpp @@ -0,0 +1,71 @@ +/* ========================================================================= + * This file is part of logging-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * logging-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include +#include + +namespace logging +{ +MemoryHandler::MemoryHandler(LogLevel level) : Handler(level) +{ + //might as well setup the map -- we could let emit take care of it, + //but this would allow for less chance of an exception getting thrown + for (size_t logLevel = 0; logLevel <= LogLevel::LOG_CRITICAL; ++logLevel) + { + mLogMap[logLevel]; + } +} + +const std::vector& MemoryHandler::getLogs(LogLevel level) const +{ + const LogMap::const_iterator iter = mLogMap.find(level); + if (iter == mLogMap.end()) + { + throw except::NoSuchKeyException(Ctxt( + "LogLevel: " + level.toString())); + } + return iter->second; +} + +void MemoryHandler::write(const std::string& str) +{ + for (LogMap::iterator iter = mLogMap.begin(); + iter != mLogMap.end(); + ++iter) + { + iter->second.push_back(str); + } +} + +void MemoryHandler::emitRecord(const LogRecord* record) +{ + io::StringStream ostr; + mFormatter->format(record, ostr); + + const std::string recordStr(ostr.stream().str()); + mLogMap[record->getLevel()].push_back(recordStr); + if (record->getLevel() != LogLevel::LOG_NOTSET) + { + mLogMap[LogLevel::LOG_NOTSET].push_back(recordStr); + } +} +} diff --git a/modules/c++/logging/source/RotatingFileHandler.cpp b/modules/c++/logging/source/RotatingFileHandler.cpp new file mode 100644 index 000000000..15b2e20c4 --- /dev/null +++ b/modules/c++/logging/source/RotatingFileHandler.cpp @@ -0,0 +1,80 @@ +/* ========================================================================= + * This file is part of logging-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * logging-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +/////////////////////////////////////////////////////////// +// RotatingFileHandler.cpp +/////////////////////////////////////////////////////////// + +#include "logging/RotatingFileHandler.h" + +using namespace logging; + +RotatingFileHandler::RotatingFileHandler(const std::string& fname, + long maxBytes, int backupCount, + LogLevel level) : + StreamHandler(level) +{ + sys::OS os; + int creationFlags; + + // create directory if one doesn't exist + if (!os.exists(fname)) + { + //see if we need to make the parent directory + std::string parDir = sys::Path::splitPath(fname).first; + if (!os.exists(parDir)) + os.makeDirectory(parDir); + } + // do rollover, so we start fresh + if (backupCount > 0) + { + for (int i = backupCount - 1; i > 0; --i) + { + std::stringstream curName; + curName << fname << "." << i; + std::stringstream nextName; + nextName << fname << "." << (i + 1); + if (os.exists(curName.str())) + { + if (os.exists(nextName.str())) + { + os.remove(nextName.str()); + } + os.move(curName.str(), nextName.str()); + } + } + std::string curName = fname + ".1"; + if (os.exists(curName)) + os.remove(curName); + os.move(fname, curName); + } + + // create log file + creationFlags = sys::File::CREATE | sys::File::TRUNCATE; + mStream.reset(new io::RotatingFileOutputStream(fname, maxBytes, + backupCount, creationFlags)); +} + +RotatingFileHandler::~RotatingFileHandler() +{ + // the StreamHandler destructor closes the stream +} diff --git a/modules/c++/logging/source/Setup.cpp b/modules/c++/logging/source/Setup.cpp new file mode 100644 index 000000000..1ccfdc464 --- /dev/null +++ b/modules/c++/logging/source/Setup.cpp @@ -0,0 +1,92 @@ +/* ========================================================================= + * This file is part of logging-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * logging-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include + +#include "logging/StreamHandler.h" +#include "logging/FileHandler.h" +#include "logging/RotatingFileHandler.h" +#include "logging/StandardFormatter.h" +#include "logging/XMLFormatter.h" + +#include "logging/Setup.h" + +std::auto_ptr +logging::setupLogger(const std::string& program, + const std::string& logLevel, + const std::string& logFile, + const std::string& logFormat, + size_t logCount, + size_t logBytes) +{ + std::auto_ptr log(new logging::Logger(program)); + + // setup logging level + std::string lev = logLevel; + str::upper(lev); + str::trim(lev); + logging::LogLevel level = (lev.empty()) ? logging::LogLevel::LOG_WARNING : + logging::LogLevel(lev); + + // setup logging formatter + std::auto_ptr formatter; + std::string file = logFile; + str::lower(file); + if (str::endsWith(file, ".xml")) + { + formatter.reset( + new logging::XMLFormatter("", "")); + } + else + { + formatter.reset(new logging::StandardFormatter(logFormat)); + } + + // setup logging handler + std::auto_ptr < logging::Handler > logHandler; + if (file.empty() || file == "console") + logHandler.reset(new logging::StreamHandler()); + else + { + // create a rotating logger + logCount = (logCount < 0) ? 0 : logCount; + logBytes = (logBytes < 0) ? 0 : logBytes; + if (logBytes > 0) + { + logHandler.reset(new logging::RotatingFileHandler(logFile, + logBytes, + logCount)); + } + // create regular logging to one file + else + { + logHandler.reset(new logging::FileHandler(logFile)); + } + } + + logHandler->setLevel(level); + logHandler->setFormatter(formatter.release()); + log->addHandler(logHandler.release(), true); + + return log; +} + diff --git a/modules/c++/logging/source/StandardFormatter.cpp b/modules/c++/logging/source/StandardFormatter.cpp new file mode 100644 index 000000000..166c7d9e0 --- /dev/null +++ b/modules/c++/logging/source/StandardFormatter.cpp @@ -0,0 +1,72 @@ +/* ========================================================================= + * This file is part of logging-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * logging-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +/////////////////////////////////////////////////////////// +// StandardFormatter.cpp +/////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include "logging/StandardFormatter.h" + +using namespace logging; + +const char StandardFormatter::DEFAULT_FORMAT[] = "[%c] %p [%t] %d ==> %m"; + +StandardFormatter::StandardFormatter(const std::string& fmt, + const std::string& prologue, + const std::string& epilogue) : + Formatter((fmt.empty()) ? DEFAULT_FORMAT : fmt, prologue, epilogue) +{ +} + +void StandardFormatter::format(const LogRecord* record, io::OutputStream& os) const +{ + std::string name = (record->getName().empty()) ? ("DEFAULT") : record->getName(); + + // populate log + long threadId = sys::getThreadID(); + std::string format = mFmt; + str::replace(format, THREAD_ID, str::toString(threadId)); + str::replace(format, LOG_NAME, name); + str::replace(format, LOG_LEVEL, record->getLevelName()); + str::replace(format, TIMESTAMP, record->getTimeStamp()); + if (record->getLineNum() >= 0) + { + str::replace(format, FILE_NAME, record->getFile()); + str::replace(format, LINE_NUM, + str::toString(record->getLineNum())); + } + else + { + str::replace(format, FILE_NAME, ""); + str::replace(format, LINE_NUM, ""); + } + str::replace(format, FUNCTION, record->getFunction()); + str::replace(format, MESSAGE, record->getMessage()); + + // write to stream + os.write(format + "\n"); +} + diff --git a/modules/c++/logging/source/StreamHandler.cpp b/modules/c++/logging/source/StreamHandler.cpp new file mode 100644 index 000000000..c7e72846c --- /dev/null +++ b/modules/c++/logging/source/StreamHandler.cpp @@ -0,0 +1,88 @@ +/* ========================================================================= + * This file is part of logging-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * logging-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +/////////////////////////////////////////////////////////// +// StreamHandler.cpp +/////////////////////////////////////////////////////////// + +#include "logging/StreamHandler.h" + +logging::StreamHandler::StreamHandler(logging::LogLevel level) : + logging::Handler(level) +{ + mStream.reset(new io::StandardOutStream()); + + // write prologue to stream + write(mFormatter->getPrologue()); +} + +logging::StreamHandler::StreamHandler(io::OutputStream* stream, + logging::LogLevel level) : + logging::Handler(level) +{ + mStream.reset(stream); + + // write prologue to stream + write(mFormatter->getPrologue()); +} + +void logging::StreamHandler::setFormatter(logging::Formatter* formatter) +{ + // end log with formatter injection + write(mFormatter->getEpilogue()); + + // delete old and reset to new + Handler::setFormatter(formatter); + + // start log with formatter injection + write(mFormatter->getPrologue()); +} + +void logging::StreamHandler::close() +{ + // end log with formatter injection + write(mFormatter->getEpilogue()); + + // delete formatter + Handler::close(); + + // kill stream + if (mStream.get()) + mStream->close(); +} +void logging::StreamHandler::write(const std::string& str) +{ + if (!str.empty()) + { + //acquire lock + mt::CriticalSection lock(&mHandlerLock); + + // write to stream + mStream->write(str); + mStream->flush(); + } +} +void logging::StreamHandler::emitRecord(const LogRecord* record) +{ + mFormatter->format(record, *mStream); + mStream->flush(); +} diff --git a/modules/c++/logging/source/XMLFormatter.cpp b/modules/c++/logging/source/XMLFormatter.cpp new file mode 100644 index 000000000..ebb6c78af --- /dev/null +++ b/modules/c++/logging/source/XMLFormatter.cpp @@ -0,0 +1,130 @@ +/* ========================================================================= + * This file is part of logging + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * logging-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ +#include +#include +#include +#include +#include "logging/XMLFormatter.h" + +// default log for xml -- +// Writing without a dom keeps the format function const, +// and saves us from creating doms for every log +const char logging::XMLFormatter::DEFAULT_FORMAT[] = +"\t\n\ +\t\t%F\n\ +\t\t%m\n\ +\t"; + +// add to this list as more characters are needed -- +// separate the xml non-safe from conversion by a comma +// +// & must be the first character, because it will replace +// all other safe characters if it came later +const char logging::XMLFormatter::XML_SAFE_CONVERSION[] + = "&,&,<,<,>,>,\",",',',\n, ,"; + + +logging::XMLFormatter::XMLFormatter() : logging::Formatter(DEFAULT_FORMAT, "", "") +{ + // TODO: Generate a better prologue that contains + // date, jobID, and other information that + // can distinguish the logs from one another +} +logging::XMLFormatter::XMLFormatter(const std::string& fmt, + const std::string& prologue, + const std::string& epilogue) : + logging::Formatter((fmt.empty()) ? DEFAULT_FORMAT : fmt, + prologue, + epilogue) +{ +} + +void logging::XMLFormatter::format(const logging::LogRecord* record, io::OutputStream& os) const +{ + // conver record + std::string name = (record->getName().empty()) ? + ("DEFAULT") : record->getName(); + std::string line = str::toString(record->getLineNum()); + std::string threadID = str::toString(sys::getThreadID()); + + + std::string xmlSC = XML_SAFE_CONVERSION; + std::vector xmlSafeConvert = str::split(xmlSC, ","); + std::vector logRecord; + + // populate vector with record + logRecord.push_back(threadID); + logRecord.push_back(name); + logRecord.push_back(record->getLevelName()); + logRecord.push_back(record->getTimeStamp()); + logRecord.push_back(record->getFile()); + logRecord.push_back(line); + logRecord.push_back(record->getFunction()); + logRecord.push_back(record->getMessage()); + + + // update record with SGML escape characters + for (size_t chr = 4; chr < logRecord.size(); chr++) + { + // every non-safe xml character pair + for (size_t xml = 0; xml < xmlSafeConvert.size(); xml += 2) + { + // convert until no more cases are found + size_t start = 0; + while (start < logRecord[chr].length()) + { + start = str::replace(logRecord[chr], + xmlSafeConvert[xml], + xmlSafeConvert[xml+1], + start); + + // incremented due to replacing + // '&' to '&' + start++; + } + } + } + + + // populate log + std::string format = mFmt; + str::replace(format, THREAD_ID, logRecord[0]); + str::replace(format, LOG_NAME, logRecord[1]); + str::replace(format, LOG_LEVEL, logRecord[2]); + str::replace(format, TIMESTAMP, logRecord[3]); + if (record->getLineNum() >= 0) + { + str::replace(format, FILE_NAME, logRecord[4]); + str::replace(format, LINE_NUM, logRecord[5]); + } + else + { + str::replace(format, FILE_NAME, ""); + str::replace(format, LINE_NUM, ""); + } + str::replace(format, FUNCTION, logRecord[6]); + str::replace(format, MESSAGE, logRecord[7]); + + // write to stream + os.write(format + "\n"); +} + diff --git a/modules/c++/logging/tests/BasicLoggerTest.cpp b/modules/c++/logging/tests/BasicLoggerTest.cpp new file mode 100644 index 000000000..296b1568c --- /dev/null +++ b/modules/c++/logging/tests/BasicLoggerTest.cpp @@ -0,0 +1,65 @@ +/* ========================================================================= + * This file is part of logging-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * logging-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include +#include +#include + +using namespace logging; +using namespace std; + +int main(int argc, char **argv) +{ + //create a logger, named 'test' + Logger logger; + + //log everything to the console + StreamHandler handler(LogLevel::LOG_DEBUG); + std::string + format = + "Thread = %t, Name = %c, Level = %p, File = %F, Method = %M, Line = %L, TimeStamp = %d, Message = %m"; + handler.setFormatter(new StandardFormatter(format)); + logger.addHandler(&handler, true); + + //log only WARNING or worse to the file + //FileHandler fileHandler("./test.log", LogLevel::LOG_WARNING); + //logger.addHandler(&fileHandler); + + logger.warn(Ctxt("WARNING Test!")); + logger.debug(Ctxt("DEBUG TEST!")); + logger.info(Ctxt("INFO TEST!")); + logger.critical(Ctxt("CRITICAL TEST!")); + + //use the global logging methods + error("global error"); + warn("global warning"); + + logger.removeHandler(&handler); + logger.warn(Ctxt("No Handlers")); + + logger.addHandler(new NullHandler, true); + logger.warn(Ctxt("Null Handler - should not log!")); + logger.addHandler(new StreamHandler(LogLevel::LOG_DEBUG), true); + logger.warn(Ctxt("WARNING Test!")); + + return 0; +} diff --git a/modules/c++/logging/tests/FactoryTest.cpp b/modules/c++/logging/tests/FactoryTest.cpp new file mode 100644 index 000000000..30230d4c0 --- /dev/null +++ b/modules/c++/logging/tests/FactoryTest.cpp @@ -0,0 +1,59 @@ +/* ========================================================================= + * This file is part of logging-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * logging-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include +#include +#include + +using namespace logging; +using namespace std; + +int main(int argc, char **argv) +{ + std::cout << LoggerFactory::getInstance().getLogger("test")->getName() << std::endl; + + Logger* logger = LoggerFactory::getInstance().getLogger("tomsLogger"); + logger->error("This should get logged to stdout"); + + LoggerFactory::getInstance().getLogger()->info("A message from the root logger."); + + //by default, the loglevel is WARN, so these won't get logged + logger->info("Info message 1"); + logger->info("Debug message 1"); + + //you can set the loglevel of a particular logger like this: + //keep in mind that this will set the level for all handlers of this Logger + logger->setLevel(LogLevel::LOG_DEBUG); + logger->info("Info message 2"); + logger->info("Debug message 2"); + + + //we can also set the default logging level, which is set statically + //It will be used for any future loggers that get created on the fly + //via the factory + DefaultLogger::setDefaultLogLevel(LogLevel::LOG_DEBUG); + logger = LoggerFactory::getInstance().getLogger("anotherLogger"); + logger->info("Info message 3"); + logger->info("Debug message 3"); + + return 0; +} diff --git a/modules/c++/logging/tests/RotatingLoggerTest.cpp b/modules/c++/logging/tests/RotatingLoggerTest.cpp new file mode 100644 index 000000000..704ef88dd --- /dev/null +++ b/modules/c++/logging/tests/RotatingLoggerTest.cpp @@ -0,0 +1,51 @@ +/* ========================================================================= + * This file is part of logging-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * logging-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include +#include +#include + +using namespace logging; +using namespace std; + +int main(int argc, char **argv) +{ + //create a logger, named 'test' + Logger *logger = new Logger("test"); + + //rotate every 1024 bytes, max of 5 backups + RotatingFileHandler handler("./rotate.log", 1024, 5); + + logger->addHandler(&handler); + + int loops = 10; + for (int i = 0; i < loops; ++i) + { + logger->warn(Ctxt("WARNING Test! ")); + logger->debug(Ctxt("DEBUG TEST! ")); + logger->info(Ctxt("INFO TEST! ")); + logger->critical(Ctxt("CRITICAL TEST! ")); + } + + delete logger; + return 0; +} diff --git a/modules/c++/logging/unittests/test_exception_logger.cpp b/modules/c++/logging/unittests/test_exception_logger.cpp new file mode 100644 index 000000000..4984269dc --- /dev/null +++ b/modules/c++/logging/unittests/test_exception_logger.cpp @@ -0,0 +1,81 @@ +/* ========================================================================= + * This file is part of logging-c++ + * ========================================================================= + * + * (C) Copyright 2013, General Dynamics - Advanced Information Systems + * + * logging-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include +#include "TestCase.h" + +class RunNothing : public sys::Runnable +{ +private: + size_t& counter; + logging::ExceptionLogger* exLog; + static sys::Mutex counterLock; +public: + RunNothing(size_t& c, logging::ExceptionLogger* el) : counter(c), exLog(el) {} + + virtual void run() + { + if(exLog->hasLogged()) + return; + + { + mt::CriticalSection crit(&counterLock); + counter++; + } + + exLog->log(except::Exception("Bad run"), logging::LogLevel::LOG_ERROR); + } +}; + +sys::Mutex RunNothing::counterLock; + +TEST_CASE(testExceptionLogger) +{ + std::auto_ptr log(new logging::Logger("test")); + std::auto_ptr + formatter(new logging::StandardFormatter("%m")); + + mem::SharedPtr exLog(new logging::ExceptionLogger(log.get())); + + size_t counter(0); + size_t numThreads(2); + + std::vector runs; + + mt::GenerationThreadPool pool(numThreads); + pool.start(); + + runs.push_back(new RunNothing(counter, exLog.get())); + pool.addAndWaitGroup(runs); + runs.clear(); + + runs.push_back(new RunNothing(counter, exLog.get())); + pool.addAndWaitGroup(runs); + runs.clear(); + + TEST_ASSERT(counter == 1); +} + +int main(int argc, char* argv[]) +{ + TEST_CHECK(testExceptionLogger); +} diff --git a/modules/c++/logging/unittests/test_rotating_log.cpp b/modules/c++/logging/unittests/test_rotating_log.cpp new file mode 100644 index 000000000..3d4d14ecc --- /dev/null +++ b/modules/c++/logging/unittests/test_rotating_log.cpp @@ -0,0 +1,121 @@ +/* ========================================================================= + * This file is part of logging-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * logging-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include +#include "TestCase.h" + +void cleanupFiles(std::string base) +{ + // cleanup + sys::OS os; + for (size_t i = 0;; ++i) + { + std::ostringstream oss; + oss << base << "." << (i + 1); + std::string fname(oss.str()); + if (os.isFile(fname)) + os.remove(fname); + else + break; + } + if (os.isFile(base)) + os.remove(base); +} + +TEST_CASE(testRotate) +{ + std::string outFile = "test_rotate.txt"; + size_t maxFiles = 5; + + cleanupFiles( outFile); + + sys::OS os; + + std::auto_ptr log(new logging::Logger("test")); + std::auto_ptr + formatter(new logging::StandardFormatter("%m")); + std::auto_ptr + logHandler(new logging::RotatingFileHandler(outFile, 10, maxFiles)); + + logHandler->setLevel(logging::LogLevel::LOG_DEBUG); + logHandler->setFormatter(formatter.release()); + log->addHandler(logHandler.release(), true); + + log->debug("0123456789"); + TEST_ASSERT(os.exists(outFile)); + TEST_ASSERT_FALSE(os.isFile(outFile + ".1")); + + log->debug("1"); + TEST_ASSERT(os.isFile(outFile + ".1")); + + cleanupFiles( outFile); +} + +TEST_CASE(testNeverRotate) +{ + std::string outFile = "test_rotate.txt"; + cleanupFiles( outFile); + + sys::OS os; + std::auto_ptr log(new logging::Logger("test")); + std::auto_ptr + formatter(new logging::StandardFormatter("%m")); + std::auto_ptr + logHandler(new logging::RotatingFileHandler(outFile)); + + for(size_t i = 0; i < 1024; ++i) + { + log->debug("test"); + } + TEST_ASSERT(os.exists(outFile)); + TEST_ASSERT_FALSE(os.isFile(outFile + ".1")); + cleanupFiles( outFile); +} + +TEST_CASE(testRotateReset) +{ + std::string outFile = "test_rotate.txt"; + cleanupFiles( outFile); + + sys::OS os; + std::auto_ptr log(new logging::Logger("test")); + std::auto_ptr + formatter(new logging::StandardFormatter("%m")); + std::auto_ptr + logHandler(new logging::RotatingFileHandler(outFile, 10)); + log->debug("01234567890"); + TEST_ASSERT(os.exists(outFile)); + TEST_ASSERT_FALSE(os.isFile(outFile + ".1")); + + log->debug("0"); + TEST_ASSERT(os.exists(outFile)); + TEST_ASSERT_FALSE(os.isFile(outFile + ".1")); + + cleanupFiles( outFile); +} + +int main(int argc, char* argv[]) +{ + TEST_CHECK( testNeverRotate); + TEST_CHECK( testRotateReset); + TEST_CHECK( testRotate); +} diff --git a/modules/c++/logging/wscript b/modules/c++/logging/wscript new file mode 100644 index 000000000..942e735c8 --- /dev/null +++ b/modules/c++/logging/wscript @@ -0,0 +1,9 @@ +NAME = 'logging' +MAINTAINER = 'jmrandol@users.sourceforge.net' +VERSION = '1.1' +MODULE_DEPS = 'io mt' + +options = configure = distclean = lambda p: None + +def build(bld): + bld.module(**globals()) diff --git a/modules/c++/math.linear/include/import/math/linear.h b/modules/c++/math.linear/include/import/math/linear.h new file mode 100644 index 000000000..43f6c62c7 --- /dev/null +++ b/modules/c++/math.linear/include/import/math/linear.h @@ -0,0 +1,32 @@ +/* ========================================================================= + * This file is part of math.linear-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * math.linear-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ +#ifndef __MATH_LINEAR_H__ +#define __MATH_LINEAR_H__ + +#include "math/linear/Eigenvalue.h" +#include "math/linear/MatrixMxN.h" +#include "math/linear/VectorN.h" +#include "math/linear/Matrix2D.h" +#include "math/linear/Vector.h" + +#endif // __MATH_LINEAR_H__ + diff --git a/modules/c++/math.linear/include/math/linear/Eigenvalue.h b/modules/c++/math.linear/include/math/linear/Eigenvalue.h new file mode 100644 index 000000000..c032e0c4f --- /dev/null +++ b/modules/c++/math.linear/include/math/linear/Eigenvalue.h @@ -0,0 +1,1218 @@ +/* ========================================================================= + * This file is part of math.linear-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * math.linear-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ +#ifndef __MATH_LINEAR_EIGENVALUE_H__ +#define __MATH_LINEAR_EIGENVALUE_H__ + +#include +#include + +#include +#include +#include +#include +#include + +namespace math +{ +namespace linear +{ +/*! + * \class Eigenvalue + * \brief Computes eigenvalues and eigenvectors of a real matrix + * + * If A is symmetric, then A = V*D*V' where the eigenvalue matrix D is + * diagonal and the eigenvector matrix V is orthogonal. That is, + * the diagonal values of D are the eigenvalues, and + * V*V' = I, where I is the identity matrix. The columns of V + * represent the eigenvectors in the sense that A*V = V*D. + * + * If A is not symmetric, then the eigenvalue matrix D is block diagonal + * with the real eigenvalues in 1-by-1 blocks and any complex eigenvalues, + * a + i*b, in 2-by-2 blocks, [a, b; -b, a]. That is, if the complex + * eigenvalues look like + + u + iv . . . . . + . u - iv . . . . + . . a + ib . . . + . . . a - ib . . + . . . . x . + . . . . . y + + * then D looks like + + u v . . . . + -v u . . . . + . . a b . . + . . -b a . . + . . . . x . + . . . . . y + * + * This keeps V a real matrix in both symmetric and non-symmetric + * cases, and A*V = V*D. + * + * The matrix V may be badly conditioned, or even singular, so the validity + * of the equation A = V*D*inverse(V) depends upon the condition number of V. + * + * This is based on the Eigenvalue class from TNT's tnt_linalg.h which + * says it was adapted from JAMA, a Java Matrix Library, developed jointly + * by the Mathworks and NIST (see http://math.nist.gov/javanumerics/jama), + * which in turn, were based on original EISPACK routines. + * + * RealT must be a real (non-complex) type + */ +template +class Eigenvalue +{ +public: + /* + * Construct the eigenvalue decomposition + * \param A Square matrix + */ + Eigenvalue(const Matrix2D& A) : + mN(A.cols()), + mD(mN), + mE(mN), + mV(mN, mN) + { + if (A.rows() != A.cols()) + { + throw except::Exception(Ctxt( + "Expected square matrix but got rows = " + + str::toString(A.rows()) + ", cols = " + + str::toString(A.cols()))); + } + + if (isSymmetric(A)) + { + mV = A; + + // Tridiagonalize. + tred2(); + + // Diagonalize. + tql2(); + } + else + { + mH = Matrix2D(mN, mN); + mOrt = Vector(mN); + + mH = A; + + // Reduce to Hessenberg form. + orthes(); + + // Reduce Hessenberg to real Schur form. + hqr2(); + } + } + + // Return the eigenvector matrix + const Matrix2D& getV() const + { + return mV; + } + + // Return the real parts of the eigenvalues + const Vector& getRealEigenvalues() + { + return mD; + } + + // Return the imaginary parts of the eigenvalues + const Vector& getImagEigenvalues() + { + return mE; + } + + /** + Computes the block diagonal eigenvalue matrix. + If the original matrix A is not symmetric, then the eigenvalue + matrix D is block diagonal with the real eigenvalues in 1-by-1 + blocks and any complex eigenvalues, + a + i*b, in 2-by-2 blocks, [a, b; -b, a]. That is, if the complex + eigenvalues look like +
+
+     u + iv     .        .          .      .    .
+     .      u - iv     .          .      .    .
+     .        .      a + ib       .      .    .
+     .        .        .        a - ib   .    .
+     .        .        .          .      x    .
+     .        .        .          .      .    y
+     
+ then D looks like +
+
+     u        v        .          .      .    .
+     -v        u        .          .      .    .
+     .        .        a          b      .    .
+     .        .       -b          a      .    .
+     .        .        .          .      x    .
+     .        .        .          .      .    y
+     
+ This keeps V a real matrix in both symmetric and non-symmetric + cases, and A*V = V*D. + + \param D: upon return, the matrix is filled with the block diagonal + eigenvalue matrix. + */ + void getD(Matrix2D& D) + { + D = Matrix2D(mN, mN, static_cast(0)); + for (int i = 0; i < mN; i++) + { + D[i][i] = mD[i]; + if (mE[i] > 0) + { + D[i][i + 1] = mE[i]; + } + else if (mE[i] < 0) + { + D[i][i - 1] = mE[i]; + } + } + } + +private: + // Symmetric Householder reduction to tridiagonal form. + void tred2() + { + // This is derived from the Algol procedures tred2 by + // Bowdler, Martin, Reinsch, and Wilkinson, Handbook for + // Auto. Comp., Vol.ii-Linear Algebra, and the corresponding + // Fortran subroutine in EISPACK. + + for (int j = 0; j < mN; j++) + { + mD[j] = mV[mN - 1][j]; + } + + // Householder reduction to tridiagonal form. + + for (int i = mN - 1; i > 0; i--) + { + + // Scale to avoid under/overflow. + + RealT scale = RealT(0.0); + RealT h = RealT(0.0); + for (int k = 0; k < i; k++) + { + scale = scale + std::abs(mD[k]); + } + if (scale == RealT(0.0)) + { + mE[i] = mD[i - 1]; + for (int j = 0; j < i; j++) + { + mD[j] = mV[i - 1][j]; + mV[i][j] = RealT(0.0); + mV[j][i] = RealT(0.0); + } + } + else + { + + // Generate Householder vector. + + for (int k = 0; k < i; k++) + { + mD[k] /= scale; + h += mD[k] * mD[k]; + } + RealT f = mD[i - 1]; + RealT g = sqrt(h); + if (f > 0) + { + g = -g; + } + mE[i] = scale * g; + h = h - f * g; + mD[i - 1] = f - g; + for (int j = 0; j < i; j++) + { + mE[j] = RealT(0.0); + } + + // Apply similarity transformation to remaining columns. + + for (int j = 0; j < i; j++) + { + f = mD[j]; + mV[j][i] = f; + g = mE[j] + mV[j][j] * f; + for (int k = j + 1; k <= i - 1; k++) + { + g += mV[k][j] * mD[k]; + mE[k] += mV[k][j] * f; + } + mE[j] = g; + } + f = RealT(0.0); + for (int j = 0; j < i; j++) + { + mE[j] /= h; + f += mE[j] * mD[j]; + } + RealT hh = f / (h + h); + for (int j = 0; j < i; j++) + { + mE[j] -= hh * mD[j]; + } + for (int j = 0; j < i; j++) + { + f = mD[j]; + g = mE[j]; + for (int k = j; k <= i - 1; k++) + { + mV[k][j] -= (f * mE[k] + g * mD[k]); + } + mD[j] = mV[i - 1][j]; + mV[i][j] = RealT(0.0); + } + } + mD[i] = h; + } + + // Accumulate transformations. + + for (int i = 0; i < mN - 1; i++) + { + mV[mN - 1][i] = mV[i][i]; + mV[i][i] = RealT(1.0); + RealT h = mD[i + 1]; + if (h != RealT(0.0)) + { + for (int k = 0; k <= i; k++) + { + mD[k] = mV[k][i + 1] / h; + } + for (int j = 0; j <= i; j++) + { + RealT g = RealT(0.0); + for (int k = 0; k <= i; k++) + { + g += mV[k][i + 1] * mV[k][j]; + } + for (int k = 0; k <= i; k++) + { + mV[k][j] -= g * mD[k]; + } + } + } + for (int k = 0; k <= i; k++) + { + mV[k][i + 1] = RealT(0.0); + } + } + for (int j = 0; j < mN; j++) + { + mD[j] = mV[mN - 1][j]; + mV[mN - 1][j] = RealT(0.0); + } + mV[mN - 1][mN - 1] = RealT(1.0); + mE[0] = RealT(0.0); + } + + // Symmetric tridiagonal QL algorithm. + + void tql2() + { + + // This is derived from the Algol procedures tql2, by + // Bowdler, Martin, Reinsch, and Wilkinson, Handbook for + // Auto. Comp., Vol.ii-Linear Algebra, and the corresponding + // Fortran subroutine in EISPACK. + + for (int i = 1; i < mN; i++) + { + mE[i - 1] = mE[i]; + } + mE[mN - 1] = RealT(0.0); + + RealT f = RealT(0.0); + RealT tst1 = RealT(0.0); + RealT eps = pow(2.0, -52.0); + for (int l = 0; l < mN; l++) + { + + // Find small subdiagonal element + + tst1 = std::max(tst1, std::abs(mD[l]) + std::abs(mE[l])); + int m = l; + + // Original while-loop from Java code + while (m < mN) + { + if (std::abs(mE[m]) <= eps * tst1) + { + break; + } + m++; + } + + // If m == l, mD[l] is an eigenvalue, + // otherwise, iterate. + + if (m > l) + { + int iter = 0; + do + { + iter = iter + 1; // (Could check iteration count here.) + + // Compute implicit shift + + RealT g = mD[l]; + RealT p = (mD[l + 1] - g) / (2.0 * mE[l]); + RealT r = hypot(p, static_cast(RealT(1.0))); + if (p < 0) + { + r = -r; + } + mD[l] = mE[l] / (p + r); + mD[l + 1] = mE[l] * (p + r); + RealT dl1 = mD[l + 1]; + RealT h = g - mD[l]; + for (int i = l + 2; i < mN; i++) + { + mD[i] -= h; + } + f = f + h; + + // Implicit QL transformation. + + p = mD[m]; + RealT c = RealT(1.0); + RealT c2 = c; + RealT c3 = c; + RealT el1 = mE[l + 1]; + RealT s = RealT(0.0); + RealT s2 = RealT(0.0); + for (int i = m - 1; i >= l; i--) + { + c3 = c2; + c2 = c; + s2 = s; + g = c * mE[i]; + h = c * p; + r = hypot(p, mE[i]); + mE[i + 1] = s * r; + s = mE[i] / r; + c = p / r; + p = c * mD[i] - s * g; + mD[i + 1] = h + s * (c * g + s * mD[i]); + + // Accumulate transformation. + + for (int k = 0; k < mN; k++) + { + h = mV[k][i + 1]; + mV[k][i + 1] = s * mV[k][i] + c * h; + mV[k][i] = c * mV[k][i] - s * h; + } + } + p = -s * s2 * c3 * el1 * mE[l] / dl1; + mE[l] = s * p; + mD[l] = c * p; + + // Check for convergence. + + } + while (std::abs(mE[l]) > eps * tst1); + } + mD[l] = mD[l] + f; + mE[l] = RealT(0.0); + } + + // Sort eigenvalues and corresponding vectors. + + for (int i = 0; i < mN - 1; i++) + { + int k = i; + RealT p = mD[i]; + for (int j = i + 1; j < mN; j++) + { + if (mD[j] < p) + { + k = j; + p = mD[j]; + } + } + if (k != i) + { + mD[k] = mD[i]; + mD[i] = p; + for (int j = 0; j < mN; j++) + { + p = mV[j][i]; + mV[j][i] = mV[j][k]; + mV[j][k] = p; + } + } + } + } + + // Nonsymmetric reduction to Hessenberg form. + + void orthes() + { + + // This is derived from the Algol procedures orthes and ortran, + // by Martin and Wilkinson, Handbook for Auto. Comp., + // Vol.ii-Linear Algebra, and the corresponding + // Fortran subroutines in EISPACK. + + int low = 0; + int high = mN - 1; + + for (int m = low + 1; m <= high - 1; m++) + { + + // Scale column. + + RealT scale = RealT(0.0); + for (int i = m; i <= high; i++) + { + scale = scale + std::abs(mH[i][m - 1]); + } + if (scale != RealT(0.0)) + { + + // Compute Householder transformation. + + RealT h = RealT(0.0); + for (int i = high; i >= m; i--) + { + mOrt[i] = mH[i][m - 1] / scale; + h += mOrt[i] * mOrt[i]; + } + RealT g = sqrt(h); + if (mOrt[m] > 0) + { + g = -g; + } + h = h - mOrt[m] * g; + mOrt[m] = mOrt[m] - g; + + // Apply Householder similarity transformation + // mH = (I-u*u'/h)*mH*(I-u*u')/h) + + for (int j = m; j < mN; j++) + { + RealT f = RealT(0.0); + for (int i = high; i >= m; i--) + { + f += mOrt[i] * mH[i][j]; + } + f = f / h; + for (int i = m; i <= high; i++) + { + mH[i][j] -= f * mOrt[i]; + } + } + + for (int i = 0; i <= high; i++) + { + RealT f = RealT(0.0); + for (int j = high; j >= m; j--) + { + f += mOrt[j] * mH[i][j]; + } + f = f / h; + for (int j = m; j <= high; j++) + { + mH[i][j] -= f * mOrt[j]; + } + } + mOrt[m] = scale * mOrt[m]; + mH[m][m - 1] = scale * g; + } + } + + // Accumulate transformations (Algol's ortran). + + for (int i = 0; i < mN; i++) + { + for (int j = 0; j < mN; j++) + { + mV[i][j] = (i == j ? RealT(1.0) : RealT(0.0)); + } + } + + for (int m = high - 1; m >= low + 1; m--) + { + if (mH[m][m - 1] != RealT(0.0)) + { + for (int i = m + 1; i <= high; i++) + { + mOrt[i] = mH[i][m - 1]; + } + for (int j = m; j <= high; j++) + { + RealT g = RealT(0.0); + for (int i = m; i <= high; i++) + { + g += mOrt[i] * mV[i][j]; + } + // Double division avoids possible underflow + g = (g / mOrt[m]) / mH[m][m - 1]; + for (int i = m; i <= high; i++) + { + mV[i][j] += g * mOrt[i]; + } + } + } + } + } + + // Complex scalar division. + static + void cdiv(RealT xr, + RealT xi, + RealT yr, + RealT yi, + RealT& cdivr, + RealT& cdivi) + { + RealT r, mD; + if (std::abs(yr) > std::abs(yi)) + { + r = yi / yr; + mD = yr + r * yi; + cdivr = (xr + r * xi) / mD; + cdivi = (xi - r * xr) / mD; + } + else + { + r = yr / yi; + mD = yi + r * yr; + cdivr = (r * xr + xi) / mD; + cdivi = (r * xi - xr) / mD; + } + } + + // Nonsymmetric reduction from Hessenberg to real Schur form. + + void hqr2() + { + + // This is derived from the Algol procedure hqr2, + // by Martin and Wilkinson, Handbook for Auto. Comp., + // Vol.ii-Linear Algebra, and the corresponding + // Fortran subroutine in EISPACK. + + // Initialize + + int nn = this->mN; + int mN = nn - 1; + int low = 0; + int high = nn - 1; + RealT eps = pow(2.0, -52.0); + RealT exshift = RealT(0.0); + RealT p = 0, q = 0, r = 0, s = 0, z = 0, t, w, x, y; + + // Store roots isolated by balanc and compute matrix norm + + RealT norm = RealT(0.0); + for (int i = 0; i < nn; i++) + { + if ((i < low) || (i > high)) + { + mD[i] = mH[i][i]; + mE[i] = RealT(0.0); + } + for (int j = std::max(i - 1, 0); j < nn; j++) + { + norm = norm + std::abs(mH[i][j]); + } + } + + // Outer loop over eigenvalue index + + int iter = 0; + while (mN >= low) + { + + // Look for single small sub-diagonal element + + int l = mN; + while (l > low) + { + s = std::abs(mH[l - 1][l - 1]) + std::abs(mH[l][l]); + if (s == RealT(0.0)) + { + s = norm; + } + if (std::abs(mH[l][l - 1]) < eps * s) + { + break; + } + l--; + } + + // Check for convergence + // One root found + + if (l == mN) + { + mH[mN][mN] = mH[mN][mN] + exshift; + mD[mN] = mH[mN][mN]; + mE[mN] = RealT(0.0); + mN--; + iter = 0; + + // Two roots found + + } + else if (l == mN - 1) + { + w = mH[mN][mN - 1] * mH[mN - 1][mN]; + p = (mH[mN - 1][mN - 1] - mH[mN][mN]) / 2.0; + q = p * p + w; + z = sqrt(std::abs(q)); + mH[mN][mN] = mH[mN][mN] + exshift; + mH[mN - 1][mN - 1] = mH[mN - 1][mN - 1] + exshift; + x = mH[mN][mN]; + + // RealT pair + + if (q >= 0) + { + if (p >= 0) + { + z = p + z; + } + else + { + z = p - z; + } + mD[mN - 1] = x + z; + mD[mN] = mD[mN - 1]; + if (z != RealT(0.0)) + { + mD[mN] = x - w / z; + } + mE[mN - 1] = RealT(0.0); + mE[mN] = RealT(0.0); + x = mH[mN][mN - 1]; + s = std::abs(x) + std::abs(z); + p = x / s; + q = z / s; + r = sqrt(p * p + q * q); + p = p / r; + q = q / r; + + // Row modification + + for (int j = mN - 1; j < nn; j++) + { + z = mH[mN - 1][j]; + mH[mN - 1][j] = q * z + p * mH[mN][j]; + mH[mN][j] = q * mH[mN][j] - p * z; + } + + // Column modification + + for (int i = 0; i <= mN; i++) + { + z = mH[i][mN - 1]; + mH[i][mN - 1] = q * z + p * mH[i][mN]; + mH[i][mN] = q * mH[i][mN] - p * z; + } + + // Accumulate transformations + + for (int i = low; i <= high; i++) + { + z = mV[i][mN - 1]; + mV[i][mN - 1] = q * z + p * mV[i][mN]; + mV[i][mN] = q * mV[i][mN] - p * z; + } + + // Complex pair + + } + else + { + mD[mN - 1] = x + p; + mD[mN] = x + p; + mE[mN - 1] = z; + mE[mN] = -z; + } + mN = mN - 2; + iter = 0; + + // No convergence yet + + } + else + { + + // Form shift + + x = mH[mN][mN]; + y = RealT(0.0); + w = RealT(0.0); + if (l < mN) + { + y = mH[mN - 1][mN - 1]; + w = mH[mN][mN - 1] * mH[mN - 1][mN]; + } + + // Wilkinson's original ad hoc shift + + if (iter == 10) + { + exshift += x; + for (int i = low; i <= mN; i++) + { + mH[i][i] -= x; + } + s = std::abs(mH[mN][mN - 1]) + std::abs(mH[mN - 1][mN - 2]); + x = y = 0.75 * s; + w = -0.4375 * s * s; + } + + // MATLAB's new ad hoc shift + + if (iter == 30) + { + s = (y - x) / 2.0; + s = s * s + w; + if (s > 0) + { + s = sqrt(s); + if (y < x) + { + s = -s; + } + s = x - w / ((y - x) / 2.0 + s); + for (int i = low; i <= mN; i++) + { + mH[i][i] -= s; + } + exshift += s; + x = y = w = 0.964; + } + } + + iter = iter + 1; // (Could check iteration count here.) + + // Look for two consecutive small sub-diagonal elements + + int m = mN - 2; + while (m >= l) + { + z = mH[m][m]; + r = x - z; + s = y - z; + p = (r * s - w) / mH[m + 1][m] + mH[m][m + 1]; + q = mH[m + 1][m + 1] - z - r - s; + r = mH[m + 2][m + 1]; + s = std::abs(p) + std::abs(q) + std::abs(r); + p = p / s; + q = q / s; + r = r / s; + if (m == l) + { + break; + } + if (std::abs(mH[m][m - 1]) * (std::abs(q) + std::abs(r)) < + eps * (std::abs(p) * + (std::abs(mH[m - 1][m - 1]) + std::abs(z) + + std::abs(mH[m + 1][m + 1])))) + { + break; + } + m--; + } + + for (int i = m + 2; i <= mN; i++) + { + mH[i][i - 2] = RealT(0.0); + if (i > m + 2) + { + mH[i][i - 3] = RealT(0.0); + } + } + + // Double QR step involving rows l:mN and columns m:mN + + for (int k = m; k <= mN - 1; k++) + { + int notlast = (k != mN - 1); + if (k != m) + { + p = mH[k][k - 1]; + q = mH[k + 1][k - 1]; + r = (notlast ? mH[k + 2][k - 1] : RealT(0.0)); + x = std::abs(p) + std::abs(q) + std::abs(r); + if (x != RealT(0.0)) + { + p = p / x; + q = q / x; + r = r / x; + } + } + if (x == RealT(0.0)) + { + break; + } + s = sqrt(p * p + q * q + r * r); + if (p < 0) + { + s = -s; + } + if (s != 0) + { + if (k != m) + { + mH[k][k - 1] = -s * x; + } + else if (l != m) + { + mH[k][k - 1] = -mH[k][k - 1]; + } + p = p + s; + x = p / s; + y = q / s; + z = r / s; + q = q / p; + r = r / p; + + // Row modification + + for (int j = k; j < nn; j++) + { + p = mH[k][j] + q * mH[k + 1][j]; + if (notlast) + { + p = p + r * mH[k + 2][j]; + mH[k + 2][j] = mH[k + 2][j] - p * z; + } + mH[k][j] = mH[k][j] - p * x; + mH[k + 1][j] = mH[k + 1][j] - p * y; + } + + // Column modification + + for (int i = 0; i <= std::min(mN, k + 3); i++) + { + p = x * mH[i][k] + y * mH[i][k + 1]; + if (notlast) + { + p = p + z * mH[i][k + 2]; + mH[i][k + 2] = mH[i][k + 2] - p * r; + } + mH[i][k] = mH[i][k] - p; + mH[i][k + 1] = mH[i][k + 1] - p * q; + } + + // Accumulate transformations + + for (int i = low; i <= high; i++) + { + p = x * mV[i][k] + y * mV[i][k + 1]; + if (notlast) + { + p = p + z * mV[i][k + 2]; + mV[i][k + 2] = mV[i][k + 2] - p * r; + } + mV[i][k] = mV[i][k] - p; + mV[i][k + 1] = mV[i][k + 1] - p * q; + } + } // (s != 0) + } // k loop + } // check convergence + } // while (mN >= low) + + // Backsubstitute to find vectors of upper triangular form + + if (norm == RealT(0.0)) + { + return; + } + + for (mN = nn - 1; mN >= 0; mN--) + { + p = mD[mN]; + q = mE[mN]; + + // RealT vector + + if (q == 0) + { + int l = mN; + mH[mN][mN] = RealT(1.0); + for (int i = mN - 1; i >= 0; i--) + { + w = mH[i][i] - p; + r = RealT(0.0); + for (int j = l; j <= mN; j++) + { + r = r + mH[i][j] * mH[j][mN]; + } + if (mE[i] < RealT(0.0)) + { + z = w; + s = r; + } + else + { + l = i; + if (mE[i] == RealT(0.0)) + { + if (w != RealT(0.0)) + { + mH[i][mN] = -r / w; + } + else + { + mH[i][mN] = -r / (eps * norm); + } + + // Solve real equations + + } + else + { + x = mH[i][i + 1]; + y = mH[i + 1][i]; + q = (mD[i] - p) * (mD[i] - p) + mE[i] * mE[i]; + t = (x * s - z * r) / q; + mH[i][mN] = t; + if (std::abs(x) > std::abs(z)) + { + mH[i + 1][mN] = (-r - w * t) / x; + } + else + { + mH[i + 1][mN] = (-s - y * t) / z; + } + } + + // Overflow control + + t = std::abs(mH[i][mN]); + if ((eps * t) * t > 1) + { + for (int j = i; j <= mN; j++) + { + mH[j][mN] = mH[j][mN] / t; + } + } + } + } + + // Complex vector + + } + else if (q < 0) + { + int l = mN - 1; + + // Last vector component imaginary so matrix is triangular + + if (std::abs(mH[mN][mN - 1]) > std::abs(mH[mN - 1][mN])) + { + mH[mN - 1][mN - 1] = q / mH[mN][mN - 1]; + mH[mN - 1][mN] = -(mH[mN][mN] - p) / mH[mN][mN - 1]; + } + else + { + RealT cdivr; + RealT cdivi; + cdiv(RealT(0.0), + -mH[mN - 1][mN], + mH[mN - 1][mN - 1] - p, + q, + cdivr, + cdivi); + mH[mN - 1][mN - 1] = cdivr; + mH[mN - 1][mN] = cdivi; + } + mH[mN][mN - 1] = RealT(0.0); + mH[mN][mN] = RealT(1.0); + for (int i = mN - 2; i >= 0; i--) + { + RealT ra, sa, vr, vi; + ra = RealT(0.0); + sa = RealT(0.0); + for (int j = l; j <= mN; j++) + { + ra = ra + mH[i][j] * mH[j][mN - 1]; + sa = sa + mH[i][j] * mH[j][mN]; + } + w = mH[i][i] - p; + + if (mE[i] < RealT(0.0)) + { + z = w; + r = ra; + s = sa; + } + else + { + l = i; + if (mE[i] == 0) + { + RealT cdivr; + RealT cdivi; + cdiv(-ra, -sa, w, q, cdivr, cdivi); + mH[i][mN - 1] = cdivr; + mH[i][mN] = cdivi; + } + else + { + + // Solve complex equations + + x = mH[i][i + 1]; + y = mH[i + 1][i]; + vr = (mD[i] - p) * (mD[i] - p) + mE[i] * mE[i] + - q * q; + vi = (mD[i] - p) * 2.0 * q; + if ((vr == RealT(0.0)) && (vi == RealT(0.0))) + { + vr = eps * norm * + (std::abs(w) + std::abs(q) + std::abs(x) + + std::abs(y) + std::abs(z)); + } + + RealT cdivr; + RealT cdivi; + cdiv(x * r - z * ra + q * sa, + x * s - z * sa - q * ra, + vr, + vi, + cdivr, + cdivi); + + mH[i][mN - 1] = cdivr; + mH[i][mN] = cdivi; + if (std::abs(x) > (std::abs(z) + std::abs(q))) + { + mH[i + 1][mN - 1] = (-ra - w * mH[i][mN - 1] + + q * mH[i][mN]) / x; + mH[i + 1][mN] = (-sa - w * mH[i][mN] + - q * mH[i][mN - 1]) / x; + } + else + { + cdiv(-r - y * mH[i][mN - 1], + -s - y * mH[i][mN], + z, + q, + cdivr, + cdivi); + + mH[i + 1][mN - 1] = cdivr; + mH[i + 1][mN] = cdivi; + } + } + + // Overflow control + + t = std::max(std::abs(mH[i][mN - 1]), + std::abs(mH[i][mN])); + if ((eps * t) * t > 1) + { + for (int j = i; j <= mN; j++) + { + mH[j][mN - 1] = mH[j][mN - 1] / t; + mH[j][mN] = mH[j][mN] / t; + } + } + } + } + } + } + + // Vectors of isolated roots + + for (int i = 0; i < nn; i++) + { + if (i < low || i > high) + { + for (int j = i; j < nn; j++) + { + mV[i][j] = mH[i][j]; + } + } + } + + // Back transformation to get eigenvectors of original matrix + + for (int j = nn - 1; j >= low; j--) + { + for (int i = low; i <= high; i++) + { + z = RealT(0.0); + for (int k = low; k <= std::min(j, high); k++) + { + z = z + mV[i][k] * mH[k][j]; + } + mV[i][j] = z; + } + } + } + + static + bool isSymmetric(const Matrix2D& A) + { + for (size_t row = 0; row < A.rows(); ++row) + { + for (size_t col = 0; col < A.cols(); ++col) + { + if (A[row][col] != A[col][row]) + { + return false; + } + } + } + + return true; + } + +private: + // Row and column dimension (square matrix). + const int mN; + + // Arrays for internal storage of eigenvalues. + Vector mD; // real part + Vector mE; // imag part + + // Array for internal storage of eigenvectors. + Matrix2D mV; + + // Array for internal storage of nonsymmetric Hessenberg form. + Matrix2D mH; + + // Working storage for nonsymmetric algorithm. + Vector mOrt; +}; +} +} + +#endif diff --git a/modules/c++/math.linear/include/math/linear/Matrix2D.h b/modules/c++/math.linear/include/math/linear/Matrix2D.h new file mode 100644 index 000000000..76407b087 --- /dev/null +++ b/modules/c++/math.linear/include/math/linear/Matrix2D.h @@ -0,0 +1,1296 @@ +/* ========================================================================= + * This file is part of math.linear-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * math.linear-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ +#ifndef __MATH_LINEAR_MATRIX_2D_H__ +#define __MATH_LINEAR_MATRIX_2D_H__ + +#include +#include +#include +#include +#include "math/linear/MatrixMxN.h" + +namespace math +{ +namespace linear +{ + +// Forward declare friend class +template +class Vector; + +/*! + * \class Matrix2D + * \brief Flexible sized Matrix template + * + * This class provides a flexible size class of arbitrary, sizable + * dimensions M and N. Invocations are not required to know the size of these matrices + * at compile time. This class is more flexible then its MatrixMxN counterpart, however + * the MatrixMxN should be favored wherever possible (in other words, whenever the + * matrix dimensions are known a priori). + * + * This class is assumed to be a mathematical matrix of small to moderate size. Memory + * allocation is managed by the ScopedArray used underneath. + * + * + */ +template +class Matrix2D +{ + friend class Vector<_T>; + + //! Matrix dimension in rows + size_t mM; + + //! Matrix dimension in cols + size_t mN; + + //! Length of storage + size_t mMN; + + //! storage owned by the object + mem::ScopedArray<_T> mStorage; + + //! pointer to the raw storage + _T *mRaw; + +public: + //! Default constructor (does nothing) + Matrix2D() : + mM(0), mN(0), mMN(0), mRaw(NULL) + { + } + + /*! + * Create a matrix with a constant value for + * each element. + * + * \param cv A constant value (defaults to 0) + * + * \code + Matrix2D mx(2, 2, 4.2f); + * \endcode + * + */ + Matrix2D(size_t M, size_t N, _T cv = 0) : + mM(M), mN(N), mMN(M*N), + mStorage(new _T[mMN]), + mRaw(mStorage.get()) + { + std::fill_n(mRaw, mMN, cv); + } + /*! + * Construct a matrix from a 1D raw M*N pointer. + * Assumes that the pointer is of correct size. + * + * \code + double raw9[] = + { + 1, 2, 3 + 4, 5, 6, + 7, 8, 8 + }; + Matrix2D<> A(3, 3, raw9); + * \endcode + * + * \param raw A raw pointer to copy internally + */ + Matrix2D(size_t M, size_t N, const _T* raw) : + mM(M), mN(N), mMN(M*N), + mStorage(new _T[mMN]), + mRaw(mStorage.get()) + { + std::copy(raw, raw+mMN, mRaw); + } + /*! + * Construct a matrix from a 1D M*N vector. + * + * \code + std::vector vec9(9, 42.0); + Matrix2D<> A(3, 3, vec9); + * \endcode + * + * + */ + Matrix2D(size_t M, size_t N, const std::vector<_T>& raw) : + mM(M), mN(N), mMN(M*N), + mStorage(new _T[mMN]), + mRaw(mStorage.get()) + { + // use mMN endpoint, since mMN can be less than raw.size() + std::copy(raw.begin(), raw.begin()+mMN, mRaw); + } + /*! + * Supports explicit assignment from + * one matrix to another + * + * \param mx A constant matrix to copy + * + * \code + Matrix2D<> At(A.transpose()); + * \endcode + */ + Matrix2D(const Matrix2D& mx) : + mM(mx.mM), mN(mx.mN), mMN(mx.mMN), + mStorage(new _T[mMN]), + mRaw(mStorage.get()) + { + std::copy(mx.mRaw, mx.mRaw+mMN, mRaw); + } + /*! + * Supports use of the class as a decorator + * for an existing pointer. The object + * may adopt the pointer, taking responsibility + * for its destruction. + * + * \code + std::vector vec9(9, 42.0); + Matrix2D<> At(3, 3, &vec9[0], false); + * \endcode + */ + Matrix2D(size_t M, size_t N, _T* raw, bool adopt) : + mM(M), mN(N), mMN(M*N), mRaw(raw) + { + if (adopt) + { + // pointer will be destroyed by us + mStorage.reset(raw); + mRaw = mStorage.get(); + } + } + + /*! + * Assignment operator from one matrix to another + * + * \code + Matrix2D<> At = A.transpose(); + * \endcode + * + * \param mx The source matrix + * \return this (the copy) + */ + Matrix2D& operator=(const Matrix2D& mx) + { + if (this != &mx) + { + mM = mx.mM; + mN = mx.mN; + mMN = mx.mMN; + + mStorage.reset(new _T[mMN]), + mRaw = mStorage.get(); + + std::copy(mx.mRaw, mx.mRaw+mMN, mRaw); + } + return *this; + } + + /*! + * Set a matrix to a single element containing the contents + * of a scalar value. Note that this behavior differs (drastically) + * from the MatrixMxN operator for a scalar value, since here, the + * dimensions cannot be known + * + * \code + Matrix2D mx = 4.3f; + assert(mx.size() == 1); + * \endcode + * + */ + Matrix2D& operator=(const _T& sv) + { + mM = 1; + mN = 1; + mMN = 1; + mStorage.reset(new _T[1]); + mRaw = mStorage.get(); + mRaw[0] = sv; + return *this; + } + + //! Nothing is allocated by us + ~Matrix2D() {} + + + /*! + * Get back the value at index i, j + * \code + double Aij = A(i, j); + * \endcode + * + * \param i The row index + * \param j The column index + */ + inline _T operator()(size_t i, size_t j) const + { +#if defined(MATH_LINEAR_BOUNDS) + assert( i < mM && j < mN ); +#endif + return mRaw[i * mN + j]; + } + + /*! + * This operator allows you to mutate an element + * at A(i, j): + * + * \code + A(i, j) = 4.3; + * \endcode + * + * \param i The ith index into the rows (M) + * \param j The jth index into the cols (N) + */ + inline _T& operator()(size_t i, size_t j) + { +#if defined(MATH_LINEAR_BOUNDS) + assert( i < mM && j < mN ); +#endif + return mRaw[i * mN + j]; + } + + /*! + * Please try to avoid this method. There is extensive information + * here about why you should avoid it: + * http://www.parashift.com/c++-faq-lite/operator-overloading.html#faq-13.10 + * http://www.parashift.com/c++-faq-lite/operator-overloading.html#faq-13.11 + */ + inline const _T* operator[](size_t i) const + { + return row(i); + } + + /*! + * Never use this method! It should not be used for the same reasons as + * its const-alternative: + * http://www.parashift.com/c++-faq-lite/operator-overloading.html#faq-13.10 + * http://www.parashift.com/c++-faq-lite/operator-overloading.html#faq-13.11 + * + * But it is even more dangerous, since the user can cause damage by unwittingly + * treating row i as a mutable pointer. + */ + inline _T* operator[](size_t i) + { + return row(i); + } + + /*! + * Get a constant pointer to a row + * + * \code + // Get second row vector + const double* rowVector = A.row(1); + * \endcode + * + */ + inline const _T* row(size_t i) const + { +#if defined(MATH_LINEAR_BOUNDS) + assert( i < mM); +#endif + return &mRaw[i * mN]; + } + + /*! + * Never use this method! This method is dangerous + * since the user can cause damage by unwittingly + * treating row i as a mutable pointer. + */ + inline _T* row(size_t i) + { +#if defined(MATH_LINEAR_BOUNDS) + assert( i < mM); +#endif + return &mRaw[i * mN]; + } + + /*! + * Set the matrix row i to a copy of + * the row vector + * + * \code + Matrix2D<> A(3, 3, 42.0); + double rowVec[] = { 1, 2, 3 }; + A.row(0, rowVec); + * \endcode + * + * \param i The row index + * \param vec The row vector to copy from + */ + inline void row(size_t i, const _T* vec_) + { + for (size_t j = 0; j < mN; j++) + { + mRaw[i * mN + j] = vec_[j]; + } + } + /*! + * Set the matrix row i to a copy of + * the row vector + * + * \code + Matrix2D<> A(3, 3, 42.0); + std::vector rowVec(3, 1.2); + A.row(0, rowVec); + * \endcode + * + * \param i The row index + * \param vec The row vector to copy from + */ + inline void row(size_t i, const std::vector<_T>& vec_) + { + if (!vec_.empty()) + { + row(i, &vec_[0]); + } + } + + /*! + * Get back the column vector at index j + * + * \code + std::vector colVec = A.col(0); + * \endcode + * + * \param j The column index + * \return A vector copy of the column + */ + std::vector<_T> col(size_t j) const + { + std::vector<_T> jth(mM); + for (size_t i = 0; i < mM; ++i) + { + jth[i] = mRaw[i * mN + j]; + } + return jth; + } + + /*! + * Set column from vector at index j + * + * \code + Matrix<3, 3> A(42.0); + double colVec[] = { 1, 2, 3 }; + A.col(0, colVec); + * \endcode + * + * \param j The column index + * \param vec The vector to copy from + */ + void col(size_t j, const _T* vec_) + { + for (size_t i = 0; i < mM; ++i) + { + mRaw[i * mN + j] = vec_[i]; + } + } + + /*! + * Set column from vector at index j + * + * \code + Matrix2D<> A(3, 3, 42.0); + std::vector colVec(3, 1.2); + A.col(0, colVec); + * \endcode + * + * \param j The column index + * \param vec The vector to copy from + */ + void col(size_t j, const std::vector<_T>& vec_) + { + if (!vec_.empty()) + { + col(j, &vec_[0]); + } + } + + //! Return number of rows (M) + size_t rows() const { return mM; } + + //! Return number of cols (N) + size_t cols() const { return mN; } + + //! Return total size (M x N) + size_t size() const { return mMN; } + + //! Get a constant ref to the underlying vector + const _T* get() const { return mRaw; } + + /*! + * Equality operator test + * + * \code + + double raw4[] = { 1, 2, 3, 4 }; + Matrix2D A(2, 2, raw4); + MatrixMxN<2, 2> B(raw4); + Matrix2D C = A; + assert( A == B ); + assert( A == C ); + + * \endcode + * + * \param mx The source matrix + * \return this (the copy) + */ + template inline bool operator==(const Matrix_T& mx) const + { + + if (rows() != mx.rows() || cols() != mx.cols()) + return false; + + size_t M = rows(); + size_t N = cols(); + for (size_t i = 0; i < M; ++i) + { + for (size_t j = 0; j < N; ++j) + { + if (! equals(mRaw[i * N + j], mx(i, j))) + return false; + } + } + return true; + } + /*! + * Non-equality operator test + * + * \code + + double raw4[] = { 1, 2, 3, 4 }; + Matrix2D A(2, 2, raw4); + MatrixMxN<2, 2> B(raw4); + B(1, 1) = 42.0; + Matrix2D C(2, 2, &B.mRaw[0][0]); + assert( A != B ); + assert( A != C ); + + * \endcode + * + * \param mx The source matrix + * \return this (the copy) + */ + template inline bool operator!=(const Matrix_T& mx) const + { + return !(*this == mx); + } + + /*! + * The scale function allows you to scale + * the matrix by a scalar value in-place. + * + * If you can afford to mutate the matrix, + * this will be more efficient than its + * multiply counterpart + * + * \code + Matrix2D mx = createIdentity(3); + mx.scale(4.2f); + * \endcode + * + * + * \param scalar The value to multiply into mx + * + */ + Matrix2D& scale(_T scalar) + { + for (size_t i = 0; i < mMN; ++i) + mRaw[i] *= scalar; + return *this; + } + + /*! + * Does a matrix-scalar multiplication. The + * output is a matrix of same dimensions. This + * function is identical to the scale() method + * except that this matrix is not mutated - + * a scale copy is produced and returned. Note that + * it is never necessary to do this function directly, + * as the multiply ('*') operator is overloaded + * + * \code + scaled = mx.multiply(scalar); + * \endcode + * + * \param scalar A scalar value + * return a scaled matrix + * + */ + Matrix2D multiply(_T scalar) const + { + Matrix2D mx = *this; + + for (size_t i = 0; i < mMN; ++i) + { + mx.mRaw[i] *= scalar; + } + return mx; + } + + /*! + * Multiply an NxP matrix to a MxN matrix (this) to + * produce an MxP matrix output. + * + * This function accesses the inner arrays for + * (potential, though slight) performance reasons. + * + * \param mx An NxP matrix + * \return An MxP matrix + * + * + * \code + Matrix2D<> a3x1(3, 1, 42.0); + Matrix2D<> a1x3(1, 3, 1.0); + Matrix2D<> a3x3(A.multiply(B)); + Matrix2D<> a1x1(B.multiply(A)); + * \endcode + * + */ + Matrix2D + multiply(const Matrix2D& mx) const + { + if (mN != mx.mM) + throw except::Exception(Ctxt( + "Invalid inner dimension sizes for multiply")); + + size_t M = mM; + size_t P = mx.mN; + + Matrix2D newM(M, P); + multiply(mx, newM); + return newM; + } + + /*! + * Multiply an NxP matrix to a MxN matrix (this) to + * produce an MxP matrix output. + * + * This function accesses the inner arrays for + * (potential, though slight) performance reasons. + * + * \param mx An NxP matrix + * \param out An MxP matrix + * + * \code + Matrix2D<> a3x1(3, 1, 42.0); + Matrix2D<> a1x3(1, 3, 1.0); + Matrix2D<> a3x3(3, 3, 0); + A.multiply(B, a3x3); + * \endcode + * + */ + void + multiply(const Matrix2D& mx, Matrix2D &out) const + { + size_t M(mM); + size_t N(mN); + size_t P(mx.mN); + + if (mN != mx.mM) + throw except::Exception(Ctxt( + "Invalid inner dimension sizes for multiply")); + if (out.mM != M) + throw except::Exception(Ctxt( + "Invalid output row size for multiply")); + if (out.mN != P) + throw except::Exception(Ctxt( + "Invalid output column size for multiply")); + + size_t i, j, k; + for (i = 0; i < M; i++) + { + for (j = 0; j < P; j++) + { + out(i, j) = 0; + + for (k = 0; k < N; k++) + { + out(i, j) += mRaw[i * N + k] * mx(k, j); + } + } + } + } + + + /*! + * Take in a matrix that is NxN and apply each diagonal + * element to the column vector. This method mutates this, + * but returns it out as well. + * + * For each column vector in this, multiply it by the scalar + * diagonal value then assign the result. + * + * \param mx An NxN matrix whose diagonals scale the columns + * \return A reference to this. + * + * \code + C = A.scaleDiagonal(diagonalMatrix); + * \endcode + * + * + */ + Matrix2D& scaleDiagonal(const Matrix2D& mx) + { + if (mx.mM != mx.mN || mx.mN != mN) + throw except::Exception(Ctxt("Invalid size for diagonal multiply")); + + size_t i, j; + for (i = 0; i < mM; i++) + { + for (j = 0; j < mN; j++) + { + mRaw[i * mN + j] *= mx(j,j); + } + } + return *this; + } + + /*! + * Same as scaleDiagonal() but takes mx in as a row vector + * + */ + Matrix2D& scaleDiagonalRowVector(const Matrix2D& mx) + { + if (mx.mM != mN || mx.mN != 1) + throw except::Exception(Ctxt("Invalid size for diagonal multiply")); + + size_t i, j; + for (i = 0; i < mM; i++) + { + for (j = 0; j < mN; j++) + { + mRaw[i * mN + j] *= mx(j,0); + } + } + return *this; + } + + /*! + * This function is the same as scaleDiagonal except that + * it does not mutate this (it makes a copy and then calls + * that function on the copy). + * + * \param mx An NxN matrix whose diagonals scale the columns + * \return a copy matrix + * + * \code + C = A.multiplyDiagonal(diagonalMatrix); + * \endcode + * + * + */ + Matrix2D + multiplyDiagonal(const Matrix2D& mx) const + { + Matrix2D newM = *this; + newM.scaleDiagonal(mx); + return newM; + } + + /*! + * This function is the same as multiplyDiagonal except that mx is a + * row vector + * + */ + Matrix2D + multiplyDiagonalRowVector(const Matrix2D& mx) const + { + Matrix2D newM = *this; + newM.scaleDiagonalRowVector(mx); + return newM; + } + + /*! + * This function does an add and accumulate + * operation. The parameter is add-assigned + * element-wise to this + * + * \param mx The matrix to assign (MxN) + * \return This + * + * \code + A += B; + * \endcode + * + */ + Matrix2D& + operator+=(const Matrix2D& mx) + { + if (mM != mx.mM || mN != mx.mN) + throw except::Exception(Ctxt("Required to equally size matrices for element-wise add")); + + for (size_t i = 0; i < mMN; ++i) + { + mRaw[i] += mx.mRaw[i]; + } + return *this; + + } + + /*! + * This function does a subtraction + * operation element wise. + * + * \param mx MxN matrix to subtract from this + * \return This + * + * \code + A -= B; + * \endcode + * + */ + Matrix2D& + operator-=(const Matrix2D& mx) + { + if (mx.mM != mM || mx.mN != mN) + throw except::Exception(Ctxt("Matrices must be same size for element-wise subtract")); + + for (size_t i = 0; i < mM; i++) + { + for (size_t j = 0; j < mN; j++) + { + mRaw[i * mN + j] -= mx(i, j); + } + } + return *this; + + } + + /*! + * Add an MxN matrix to another and return a third + * that is the sum. This operation does not mutate this. + * + * \param mx + * \return The sum + * + * \code + C = A.add(B); + * \endcode + * + */ + Matrix2D add(const Matrix2D& mx) const + { + Matrix2D newM = *this; + newM += mx; + return newM; + } + + /*! + * Subtract an MxN matrix to another and return a third + * that is the sum. This operation does not mutate this. + * + * \param mx + * \return The sum + * + * \code + C = A.subtract(B); + * \endcode + * + */ + + Matrix2D subtract(const Matrix2D& mx) const + { + Matrix2D newM = *this; + newM -= mx; + return newM; + } + + + /*! + * Create a NxM matrix which is the transpose of this + * MxN matrix. + * + * \return An NxM matrix that is the transpose + * + * \code + B = A.tranpose(); + * \endcode + * + */ + Matrix2D transpose() const + { + + Matrix2D x(mN, mM); + for (size_t i = 0; i < mM; i++) + for (size_t j = 0; j < mN; j++) + x.mRaw[j * mM + i] = mRaw[i * mN + j]; + + return x; + } + + /*! + * Does LU decomposition on a matrix. + * In order to do this efficiently, we get back + * as a return value a copy of the matrix that is + * decomposed, but we also produce the pivots for + * permutation. This function is used for the generalized + * inverse. + * + * This function is based on the TNT LU decomposition + * function. + * + * \param [out] pivotsM (pre sized) + * + */ + Matrix2D decomposeLU(std::vector& pivotsM) const + { + + Matrix2D lu(mM, mN); + + for (size_t i = 0; i < mM; i++) + { + // Start by making our pivots unpermuted + pivotsM[i] = i; + for (size_t j = 0; j < mN; j++) + { + // And copying elements + lu.mRaw[i * mN + j] = mRaw[i * mN + j]; + } + } + + std::vector<_T> colj(mM); + _T* rowi; + + for (size_t j = 0; j < mN; j++) + { + for (size_t i = 0; i < mM; i++) + { + colj[i] = lu(i, j); + } + + for (size_t i = 0; i < mM; i++) + { + rowi = lu[i]; + + size_t max = std::min(i, j); + _T s(0); + for (size_t k = 0; k < max; k++) + { + s += rowi[k] * colj[k]; + } + colj[i] -= s; + rowi[j] = colj[i]; + + } + + size_t p = j; + for (size_t i = j + 1; i < mM; i++) + { + if (std::abs(colj[i]) > std::abs(colj[p])) + p = i; + + } + if (p != j) + { + size_t k = 0; + for (; k < mN; k++) + { + // We are swapping + _T t = lu(p, k); + lu(p, k) = lu(j, k); + lu(j, k) = t; + } + k = pivotsM[p]; + pivotsM[p] = pivotsM[j]; + pivotsM[j] = k; + } + if (j < mM && std::abs( lu(j, j) )) + { + for (size_t i = j + 1; i < mM; i++) + { + // Divide out our rows + lu(i, j) /= lu(j, j); + } + } + + } + + return lu; + } + + /*! + * Permute a matrix from pivots. This funtion does + * not mutate this. + * + * \param pivotsM The M pivots vector + * \param n The number of columns (defaults to this' N) + * \return A copy of this matrix that is permuted + * + * \code + int p[2] = { 1, 0 }; + Matrix2D G = F.permute(P); + * \endcode + * + */ + Matrix2D permute(const std::vector& pivotsM, size_t n = 0) const + { + if (n == 0) n = mN; + Matrix2D perm(mM, n); + for (size_t i = 0; i < mM; i++) + { + for (size_t j = 0; j < n; j++) + { + perm(i, j) = mRaw[pivotsM[i] * mN + j]; + } + } + return perm; + } + + /*! + * Find the L2 norm of the matrix. + * \return The norm + */ + _T norm() const + { + size_t sz = mM * mN; + _T acc(0); + for (size_t i = 0; i < sz; ++i) + { + acc += mRaw[i] * mRaw[i]; + } + return (_T)::sqrt((const _T)acc); + } + + /*! + * Scale the entire matrix inplace by the L2 norm value. + * \return A reference to this + */ + Matrix2D& normalize() + { + return scale(1.0/norm()); + } + /*! + * Alias for this->add(); + * + * \code + C = A + B; + * \endcode + * + */ + Matrix2D operator+(const Matrix2D& mx) const + { + return add(mx); + } + + + /*! + * Alias for this->subtract(); + * + * \code + C = A - B; + * \endcode + * + */ + Matrix2D operator-(const Matrix2D& mx) const + { + return subtract(mx); + } + + /*! + * Alias for this->multiply(scalar); + * + * \code + scaled = A * scalar; + * \endcode + * + */ + Matrix2D operator*(_T scalar) const + { + + return multiply(scalar); + } + + /*! + * Alias for this->multiply(1/scalar); + * + * \code + scaled = A / scalar; + * \endcode + * + */ + Matrix2D operator/(_T scalar) const + { + + return multiply(1/scalar); + } + + /*! + * Alias for this->multiply(NxP); + * + * \code + C = A * B; + * \endcode + */ + Matrix2D + operator*(const Matrix2D& mx) const + { + return multiply(mx); + } + + +}; + +/*! + * This function creates an identity matrix of size NxN and type _T + * with 1's in the diagonals. + * + * \code + Matrix2D = identityMatrix(4); + * \endcode + * + * \param N the dimension in rows and in cols for the matrix to be produced + * + */ +template Matrix2D<_T> + identityMatrix(size_t N) +{ + Matrix2D<_T> mx(N, N); + for (size_t i = 0; i < N; i++) + { + for (size_t j = 0; j < N; j++) + { + mx(i, j) = (i == j) ? 1: 0; + } + } + return mx; +} + +template Matrix2D<_T> + diagonalMatrix(const Vector_T& diag) +{ + size_t N = diag.size(); + + Matrix2D<_T> mx(N, N, 0.0); + for (size_t i = 0; i < N; ++i) + { + mx(i, i) = diag[i]; + } + return mx; +} + +/*! + * Solve Ax = b using LU decomposed matrix and the permutation vector. + * Method based on TNT + * + */ +template + math::linear::Matrix2D<_T> solveLU(const std::vector& pivotsM, + const Matrix2D<_T> &lu, + const Matrix2D<_T> &b) +{ + + + // If we dont have something in the diagonal, we can't solve this + math::linear::Matrix2D<_T> x = b.permute(pivotsM); + + const size_t P = b.cols(); + const size_t N = lu.cols(); + for (size_t kk = 0; kk < N; kk++) + { + for (size_t ii = kk + 1; ii < N; ii++) + { + for (size_t jj = 0; jj < P; jj++) + { + x(ii, jj) -= x(kk, jj)*lu(ii, kk); + } + } + } + for (sys::SSize_T kk = N - 1; kk >= 0; kk--) + { + for (size_t jj = 0; jj < P; jj++) + { + x(kk, jj) /= lu(kk, kk); + } + + for (size_t ii = 0; ii < static_cast(kk); ii++) + { + // This one could be _Q + for (size_t jj = 0; jj < P; jj++) + { + x(ii, jj) -= x(kk, jj)*lu(ii, kk); + } + } + } + + return x; +} + +/*! + * Perform hard-coded 2x2 matrix inversion. You can use this method + * directly, or the inverse() operator which will automatically call + * this for 2x2s + * + */ +template inline Matrix2D<_T> inverse2x2(const Matrix2D<_T>& mx) +{ + Matrix2D<_T> inv(2, 2); + double determinant = mx(1,1) * mx(0,0) - mx(1,0)*mx(0,1); + + if (equals(determinant, 0.0)) + throw except::Exception(Ctxt("Non-invertible matrix!")); + + // Standard 2x2 inverse + inv(0,0) = mx(1,1); + inv(0,1) = -mx(0,1); + inv(1,0) = -mx(1,0); + inv(1,1) = mx(0,0); + + inv.scale( 1.0 / determinant ); + return inv; +} + +/*! + * Perform hard-coded 3x3 matrix inversion. You can use this method + * directly, or the inverse() operator which will automatically call + * this for 3x3s + * + */ +template inline Matrix2D<_T> + inverse3x3(const Matrix2D<_T>& mx) +{ + Matrix2D inv(3, 3); + + double a = mx(0,0); + double b = mx(0,1); + double c = mx(0,2); + + double d = mx(1,0); + double e = mx(1,1); + double f = mx(1,2); + + double g = mx(2,0); + double h = mx(2,1); + double i = mx(2,2); + + double g1 = e*i - f*h; + double g2 = d*i - f*g; + double g3 = d*h - e*g; + + double determinant = + a*g1 - b*g2 + c*g3; + + if (equals(determinant, 0.0)) + throw except::Exception(Ctxt("Non-invertible matrix!")); + + + inv(0,0) = g1; inv(0,1) = c*h - b*i; inv(0,2) = b*f - c*e; + inv(1,0) = -g2; inv(1,1) = a*i - c*g; inv(1,2) = c*d - a*f; + inv(2,0) = g3; inv(2,1) = b*g - a*h; inv(2,2) = a*e - b*d; + inv.scale( 1.0 / determinant ); + + return inv; + +} + + +/*! + * Generalized inverse method (currently uses LU decomposition). + * + * \param mx A matrix to invert + * + * \code + Matrix2D<> Ainv = inverseLU(A); + * \endcode + * + */ +template inline + Matrix2D<_T> inverseLU(const Matrix2D<_T>& mx) +{ + + + size_t M = mx.rows(); + size_t N = mx.cols(); + Matrix2D<_T> a(M, M, (_T)0); + + for (size_t i = 0; i < M; i++) + a(i, i) = 1; + + std::vector pivots(M); + Matrix2D<_T> lu = mx.decomposeLU(pivots); + + for (size_t i = 0; i < N; i++) + { + if ( equals<_T>(lu(i, i), 0) ) + throw except::Exception(Ctxt("Non-invertible matrix!")); + } + + return solveLU(pivots, lu, a); + +} + +/*! + * Generalized inverse function. This function has special + * cases for 2x2s and 3x3s. Otherwise, it uses generalized + * LU decomposition to solve for the inverse. + * + * \code + Matrix2D<> Ainv = inverse(A); + * \endcode + */ +template inline + Matrix2D<_T> inverse(const Matrix2D<_T>& mx) +{ + // Try to speed this up + if (mx.rows() != mx.cols()) + throw except::Exception(Ctxt("Expected a square matrix")); + if (mx.rows() == 2) + return inverse2x2<_T>(mx); + if (mx.rows() == 3) + return inverse3x3<_T>(mx); + // TODO Add 4x4 + + return inverseLU<_T>(mx); +} +} +} + +template math::linear::Matrix2D<_T> + operator*(_T scalar, const math::linear::Matrix2D<_T>& m) +{ + return m.multiply(scalar); +} + +/*! + * Try to pretty print the Matrix to an ostream. + * \return Reference to ostream + */ +template + std::ostream& operator<<(std::ostream& os, + const math::linear::Matrix2D<_T>& m) +{ + + + size_t i, j; + os << "(" << m.rows() << ',' << m.cols() << ")" << std::endl; + for (i = 0; i < m.rows(); ++i) + { + for (j = 0; j < m.cols(); ++j) + { + os << std::setw(10) << m(i, j) << " "; + } + os << std::endl; + } + + + return os; +} + + +#endif diff --git a/modules/c++/math.linear/include/math/linear/MatrixMxN.h b/modules/c++/math.linear/include/math/linear/MatrixMxN.h new file mode 100644 index 000000000..7b8cedee9 --- /dev/null +++ b/modules/c++/math.linear/include/math/linear/MatrixMxN.h @@ -0,0 +1,1451 @@ +/* ========================================================================= + * This file is part of math.linear-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * math.linear-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ +#ifndef __MATH_LINEAR_MATRIX_M_X_N_H__ +#define __MATH_LINEAR_MATRIX_M_X_N_H__ + +#include +#include + +namespace math +{ +namespace linear +{ + +// Create a safe comparison +template bool equals(const _T& e1, const _T& e2) +{ + return e1 == e2; +} + +template inline bool equals(const _T& e1, const _T& e2, _T eps) +{ + return std::abs(e1 - e2) < eps; +} + +template<> inline bool equals(const float& e1, const float& e2) +{ + return equals(e1, e2, std::numeric_limits::epsilon()); +} +template<> inline bool equals(const double& e1, const double& e2) +{ + // Its a really bold assertion here to say numeric_limits + return equals(e1, e2, std::numeric_limits::epsilon()); +} + +/*! + * \class MatrixMxN + * \brief Compile-time fixed size Matrix template + * + * This class provides a compile time fixed size class of arbitrary + * dimensions M and N. Any invocation of this class is therefore required + * to know the absolute size of the matrix at compile time. This class should + * always be used instead of Matrix2D when possible, as it should perform much + * better than its flexible-sized alternative. Use Matrix2D only when the matrix + * dimensions cannot be known at compile time + * + * Attempts are made where possible to take advantage of the fixed size, + * providing full specialization where possible. Additionally, it is + * expected that, during compilation loops may be unrolled by the compiler, + * given the right optimization settings. To faciliate compiler optimizations, + * the internal storage of the class is as a two-dimensional vector, + * following the Rationale presented in the AMD Software Optimization Guide + * for AMD64 Processors 25112 Rev. 3.06 (see chapter 2.2). Over time, the + * headers will be extended to support LAPACK implementation routine + * + * The class attempts to provide an intuitive interface for matrices, while + * achieving reasonable performance and optimizations where possible. It does + * not attempt to provide a comprehensive solution for every matrix problem, + * but it does try to handle practical problems gracefully. Efforts are made + * to make this class compatible with STL and raw C pointers where possible. + * + * The doxygen attempts to demonstrate the functionality of the class, though the + * source code and unit tests should be consulted for example usage as well. + * + */ +template +class MatrixMxN +{ + + typedef MatrixMxN<_MD, _ND, _T> Like_T; +public: + //! Public but really should be avoided + _T mRaw[_MD][_ND]; + + /*! + * No initialization here! + * + */ + MatrixMxN() + { + } + + /*! + * Create a matrix with a constant value for + * each element. + * + * \param cv A constant value (defaults to 0) + * + * \code + MatrixMxN<2, 2> mx(4.2); + * \endcode + * + */ + MatrixMxN(_T cv) + { + for (size_t i = 0; i < _MD; i++) + { + for (size_t j = 0; j < _ND; j++) + { + mRaw[i][j] = cv; + } + } + } + + + /*! + * Construct a matrix from a 1D raw M*N pointer. + * Assumes that the pointer is of correct size. + * + * \code + double raw9[] = + { + 1, 2, 3 + 4, 5, 6, + 7, 8, 8 + }; + MatrixMxN<3, 3> A(raw9); + * \endcode + * + * \param raw A raw pointer to copy internally + */ + MatrixMxN(const _T* raw) + { + for (size_t i = 0; i < _MD; i++) + { + for (size_t j = 0; j < _ND; j++) + { + mRaw[i][j] = raw[i * _ND + j]; + } + } + } + + /*! + * Construct a matrix from a 1D M*N vector. + * + * \code + std::vector vec9(9, 42.0); + MatrixMxN<3, 3> A(vec9); + * \endcode + * + * + */ + MatrixMxN(const std::vector<_T>& raw) + { + if (raw.size() < size()) + throw except::Exception(Ctxt("Invalid size exception")); + + for (size_t i = 0; i < _MD; ++i) + { + for (size_t j = 0; j < _ND; ++j) + { + mRaw[i][j] = raw[i * _ND + j]; + } + } + } + + /*! + * Supports explicit assignment from + * one matrix to another + * + * + * \param mx A constant matrix to copy + * + * \code + MatrixMxN<3, 3> At(A.transpose()); + * \endcode + */ + MatrixMxN(const MatrixMxN& mx) + { + for (size_t i = 0; i < _MD; i++) + { + for (size_t j = 0; j < _ND; j++) + { + mRaw[i][j] = mx.mRaw[i][j]; + } + } + } + /*! + * Assign a matrix from a 1D raw M*N pointer. + * Assumes that the pointer is of correct size. + * + * \code + double raw9[] = + { + 1, 2, 3 + 4, 5, 6, + 7, 8, 8 + }; + MatrixMxN<3, 3> A = raw9; + * \endcode + * + * \param raw A raw pointer to copy internally + */ + MatrixMxN& operator=(const _T* raw) + { + for (size_t i = 0; i < _MD; i++) + { + for (size_t j = 0; j < _ND; j++) + { + mRaw[i][j] = raw[i * _ND + j]; + } + } + return *this; + } + + /*! + * Assign a matrix from a 1D M*N vector. + * + * \code + std::vector vec9(9, 42.0); + MatrixMxN<3, 3> A = vec9; + * \endcode + * + * + */ + MatrixMxN& operator=(const std::vector<_T>& raw) + { + if (raw.size() < size()) + throw except::Exception(Ctxt("Invalid size exception")); + for (size_t i = 0; i < _MD; i++) + { + for (size_t j = 0; j < _ND; j++) + { + mRaw[i][j] = raw[i * _ND + j]; + } + } + return *this; + } + + + /*! + * Assignment operator from one matrix to another + * + * \code + MatrixMxN<3, 3> At = A.transpose(); + * \endcode + * + * \param mx The source matrix + * \return this (the copy) + */ + MatrixMxN& operator=(const MatrixMxN& mx) + { + if (this != &mx) + for (size_t i = 0; i < _MD; i++) + { + for (size_t j = 0; j < _ND; j++) + { + mRaw[i][j] = mx.mRaw[i][j]; + } + } + return *this; + } + + /*! + * Set a matrix (each element) to the contents + * of a scalar value. Be careful to make sure + * that the compiler knows that the right-hand side + * is of matching type to this matrix, otherwise + * it may not be able to determine if this is the + * scalar operation or a raw pointer; + * + * \code + Matrix<3, 3, float> mx = 4.3f; + * \endcode + * + */ + MatrixMxN& operator=(const _T& sv) + { + for (size_t i = 0; i < _MD; i++) + { + for (size_t j = 0; j < _ND; j++) + { + mRaw[i][0] = sv; + } + } + return *this; + } + + //! Destructor + ~MatrixMxN() {} + + + /*! + * Get back the value at index i, j + * \code + double Aij = A(i, j); + * \endcode + * + * \param i The row index + * \param j The column index + */ + inline _T operator()(size_t i, size_t j) const + { +#if defined(MATH_LINEAR_BOUNDS) + assert( i < _MD && j < _ND ); +#endif + return mRaw[i][j]; + } + /*! + * This operator allows you to mutate an element + * at A(i, j): + * + * \code + A(i, j) = 4.3; + * \endcode + * + * \param i The ith index into the rows (M) + * \param j The jth index into the cols (N) + */ + inline _T& operator()(size_t i, size_t j) + { +#if defined(MATH_LINEAR_BOUNDS) + assert( i < _MD && j < _ND ); +#endif + return mRaw[i][j]; + } + + /*! + * Please try to avoid this method. There is extensive information + * here about why you should not use it: + * http://www.parashift.com/c++-faq-lite/operator-overloading.html#faq-13.10 + * http://www.parashift.com/c++-faq-lite/operator-overloading.html#faq-13.11 + */ + inline const _T* operator[](size_t i) const + { + return row(i); + } + + /*! + * Never use this method! It should not be used for the same reasons as + * its const-alternative: + * http://www.parashift.com/c++-faq-lite/operator-overloading.html#faq-13.10 + * http://www.parashift.com/c++-faq-lite/operator-overloading.html#faq-13.11 + * + * But it is even more dangerous, since the user can cause damage by unwittingly + * treating row i as a mutable pointer. This method is only preserved for compatibility + */ + inline _T* operator[](size_t i) + { + return row(i); + } + + /*! + * Get a constant pointer to a row + * + * \code + // Get second row vector + const double* rowVector = A.row(1); + * \endcode + * + */ + inline const _T* row(size_t i) const + { +#if defined(MATH_LINEAR_BOUNDS) + assert( i < _MD); +#endif + return mRaw[i]; + } + + /*! + * Never use this method! This method is dangerous + * since the user can cause damage by unwittingly + * treating row i as a mutable pointer. + */ + inline _T* row(size_t i) + { +#if defined(MATH_LINEAR_BOUNDS) + assert( i < _MD); +#endif + return mRaw[i]; + } + + /*! + * Set the matrix row i to a copy of + * the row vector + * + * \code + Matrix<3, 3> A(42.0); + double rowVec[] = { 1, 2, 3 }; + A.row(0, rowVec); + * \endcode + * + * \param i The row index + * \param vec The row vector to copy from + */ + inline void row(size_t i, const _T* vec) + { + for (size_t j = 0; j < _ND; j++) + { + mRaw[i][j] = vec[j]; + } + } + + /*! + * Set the matrix row i to a copy of + * the row vector + * + * \code + Matrix<3, 3> A(42.0); + std::vector rowVec(3, 1.2); + A.row(0, rowVec); + * \endcode + * + * \param i The row index + * \param vec The row vector to copy from + */ + inline void row(size_t i, const std::vector<_T>& vec) + { + row(i, &vec[0]); + } + + + /*! + * Get back the column vector at index j + * + * \code + std::vector colVec = A.col(0); + * \endcode + * + * \param j The column index + * \return A vector copy of the column + */ + std::vector<_T> col(size_t j) const + { + std::vector<_T> jth(_MD); + for (size_t i = 0; i < _MD; ++i) + { + jth[i] = mRaw[i][j]; + } + return jth; + } + + + /*! + * Set column from vector at index j + * + * \code + Matrix<3, 3> A(42.0); + double colVec[] = { 1, 2, 3 }; + A.col(0, colVec); + * \endcode + * + * \param j The column index + * \param vec The vector to copy from + */ + void col(size_t j, const _T* vec) + { + + for (size_t i = 0; i < _MD; ++i) + { + mRaw[i][j] = vec[i]; + } + } + + /*! + * Set column from vector at index j + * + * \code + Matrix<3, 3> A(42.0); + std::vector colVec(3, 1.2); + A.col(0, colVec); + * \endcode + * + * \param j The column index + * \param vec The vector to copy from + */ + void col(size_t j, std::vector<_T>& vec) + { + col(j, &vec[0]); + } + + + /*! + * This function is not really necessary since presumably + * the caller knows the dims, but it is helpful for + * template functions where the exact matrix type is + * not know (e.g., MatrixMxN vs. Matrix2D + * + * It is assumed that the compiler, in most cases can + * hardcode in the proper value of _MD, though this has + * not been verified + * + * \return _MD + */ + inline size_t rows() const { return _MD; } + + /*! + * This function is not really necessary, but + * might be handy if you have some template code + * + * It is assumed that the compiler, in most cases can + * hardcode in the proper value of _ND, though this has + * not been verified + * + * \return _ND + */ + inline size_t cols() const { return _ND; } + + /*! + * Gives back the value full size of the matrix + * + * \return _MD * _ND + */ + inline size_t size() const { return _MD * _ND; } + + + + /*! + * Equality operator test + * + * \code + + double raw4[] = { 1, 2, 3, 4 }; + Matrix<2, 2> A(raw4); + Matrix2D B(2, 2, raw4); + Matrix<2, 2> C = A; + assert( A == B ); + assert( A == C ); + + * \endcode + * + * \param mx The source matrix + * \return this (the copy) + */ + + template inline bool operator==(const Matrix_T& mx) const + { + + if (_MD != mx.rows() || _ND != mx.cols()) + return false; + + for (size_t i = 0; i < _MD; ++i) + { + for (size_t j = 0; j < _ND; ++j) + { + if (! equals(mRaw[i][j], mx(i, j))) + return false; + } + } + return true; + } + + /*! + * Non-equality operator test + * + * \code + + double raw4[] = { 1, 2, 3, 4 }; + Matrix<2, 2> A(raw4); + Matrix2D B(2, 2, raw4); + B(1, 1) = 42.0; + Matrix<2, 2> C(B.vec()); + assert( A != B ); + assert( A != C ); + + * \endcode + * + * \param mx The source matrix + * \return this (the copy) + */ + + template inline bool operator!=(const Matrix_T& mx) const + { + return !(*this == mx); + } + + /*! + * The scale function allows you to scale + * the matrix by a scalar value in-place. + * + * If you can afford to mutate the matrix, + * this will be more efficient than its + * multiply counterpart + * + * \code + Matrix<3, 3> mx = createIdentity<3, double>(); + mx.scale(4.2f); + * \endcode + * + * + * \param scalar The value to multiply into mx + * \return This object + * + */ + MatrixMxN& scale(_T scalar) + { + for (size_t i = 0; i < _MD; i++) + { + for (size_t j = 0; j < _ND; j++) + { + mRaw[i][j] *= scalar; + } + } + return *this; + } + + /*! + * Does a matrix-scalar multiplication. The + * output is a matrix of same dimensions. This + * function is identical to the scale() method + * except that this matrix is not mutated - + * a scale copy is produced and returned. Note that + * it is never necessary to do this function directly, + * as the multiply ('*') operator is overloaded + * + * \code + scaled = mx.multiply(scalar); + * \endcode + * + * \param scalar A scalar value + * return a scaled matrix + * + */ + MatrixMxN<_MD, _ND> multiply(_T scalar) const + { + MatrixMxN<_MD, _ND> mx = *this; + for (size_t i = 0; i < _MD; i++) + { + for (size_t j = 0; j < _ND; j++) + { + mx[i][j] *= scalar; + } + } + return mx; + } + + /*! + * Multiply an NxP matrix to a MxN matrix (this) to + * produce an MxP matrix output. This function will + * fail at compile time if the input and output matrix + * dimensions are incorrect. + * + * This function accesses the inner arrays for + * (potential, though slight) performance reasons. + * + * One would hope that the compiler will unroll these + * loops since they are of constant size. + * + * \param mx An NxP matrix + * \return An MxP matrix + * + * + * \code + MatrixMxN<3, 1> A(42.0); + MatrixMxN<1, 3> B(1.0); + MatrixMxN<3, 3> C(A.multiply(B)); + MatrixMxN<1, 1> D(B.multiply(A)); + * \endcode + * + */ + template MatrixMxN<_MD, _PD, _T> + multiply(const MatrixMxN<_ND, _PD, _T>& mx) const + { + MatrixMxN<_MD, _PD, _T> newM; + size_t i, j, k; + + for (i = 0; i < _MD; i++) + { + for (j = 0; j < _PD; j++) + { + newM.mRaw[i][j] = 0; + for (k = 0; k < _ND; k++) + { + newM.mRaw[i][j] += mRaw[i][k] * mx.mRaw[k][j]; + } + } + } + return newM; + + } + + + /*! + * Take in a matrix that is NxN and apply each diagonal + * element to the column vector. This method mutates this, + * but returns it out as well. + * + * For each column vector in this, multiply it by the scalar + * diagonal value then assign the result. + * + * \param mx An NxN matrix whose diagonals scale the columns + * \return A reference to this. + * + * \code + C = A.scaleDiagonal(diagonalMatrix); + * \endcode + * + * + */ + MatrixMxN& scaleDiagonal(const MatrixMxN<_ND, _ND, _T>& mx) + { + size_t i, j; + for (i = 0; i < _MD; i++) + { + for (j = 0; j < _ND; j++) + { + mRaw[i][j] *= mx.mRaw[j][j]; + } + } + return *this; + } + + /*! + * This function is the same as scaleDiagonal except that + * it does not mutate this (it makes a copy and then calls + * that function on the copy). + * + * \param mx An NxN matrix whose diagonals scale the columns + * \return a copy matrix + * + * \code + C = A.multiplyDiagonal(diagonalMatrix); + * \endcode + * + * + */ + MatrixMxN<_MD, _ND, _T> + multiplyDiagonal(const MatrixMxN<_ND, _ND, _T>& mx) const + { + MatrixMxN<_MD, _ND, _T> newM = *this; + newM.scaleDiagonal(mx); + return newM; + } + + /*! + * This function does an add and accumulate + * operation. The parameter is add-assigned + * element-wise to this. + * + * This method generates a + * compile time error if the matrix dimensions + * do not agree + * + * \param mx The matrix to assign (MxN) + * \return This + * + * \code + A += B; + * \endcode + * + */ + Like_T& + operator+=(const Like_T& mx) + { + Like_T newM; + for (size_t i = 0; i < _MD; i++) + { + for (size_t j = 0; j < _ND; j++) + { + mRaw[i][j] += mx.mRaw[i][j]; + } + } + return *this; + + } + + /*! + * This function does a subtraction + * operation element wise. + * + * This method generates a + * compile time error if the matrix dimensions + * do not agree + * + * \param mx MxN matrix to subtract from this + * \return This + * + * \code + A -= B; + * \endcode + * + */ + Like_T& + operator-=(const Like_T& mx) + { + for (size_t i = 0; i < _MD; i++) + { + for (size_t j = 0; j < _ND; j++) + { + mRaw[i][j] -= mx(i, j); + } + } + return *this; + + } + + /*! + * Add an MxN matrix to another and return a third + * that is the sum. This operation does not mutate this. + * You can use the overloaded ('+') operator instead + * + * This method generates a + * compile time error if the matrix dimensions + * do not agree + * + * \param mx + * \return The sum + * + * \code + C = A.add(B); + * \endcode + * + */ + Like_T add(const Like_T& mx) const + { + Like_T newM = *this; + newM += mx; + return newM; + } + + /*! + * Subtract an MxN matrix to another and return a third + * that is the sum. This operation does not mutate this. + * You can use the overloaded ('-') operator instead + * + * This method generates a + * compile time error if the matrix dimensions + * do not agree + * + * \param mx + * \return The sum + * + * \code + C = A.subtract(B); + * \endcode + * + */ + + Like_T subtract(const Like_T& mx) const + { + Like_T newM = *this; + newM -= mx; + return newM; + } + + /*! + * Create a NxM matrix which is the transpose of this + * MxN matrix. This method generates a compiler error + * if the output matrix dimensions are not NxM + * + * \return An NxM matrix that is the transpose + * + * \code + B = A.tranpose(); + * \endcode + * + */ + MatrixMxN<_ND, _MD, _T> transpose() const + { + + MatrixMxN<_ND, _MD, _T> x; + for (size_t i = 0; i < _MD; i++) + for (size_t j = 0; j < _ND; j++) + x.mRaw[j][i] = mRaw[i][j]; + + return x; + } + + /*! + * Does LU decomposition on a matrix. + * In order to do this efficiently, we get back + * as a return value a copy of the matrix that is + * decomposed, but we also produce the pivots for + * permutation. This function is used for the generalized + * inverse. + * + * This function is based on the TNT LU decomposition + * function. + * + * \param [out] pivotsM + * + */ + Like_T decomposeLU(std::vector& pivotsM) const + { + + Like_T lu; + + for (size_t i = 0; i < _MD; i++) + { + // Start by making our pivots unpermuted + pivotsM[i] = i; + for (size_t j = 0; j < _ND; j++) + { + // And copying elements + lu(i, j) = mRaw[i][j]; + } + } + + + std::vector<_T> colj(_MD); + _T* rowi; + for (size_t j = 0; j < _ND; j++) + { + for (size_t i = 0; i < _MD; i++) + { + colj[i] = lu(i, j); + } + + for (size_t i = 0; i < _MD; i++) + { + rowi = lu[i]; + + size_t kmax = std::min(i, j); + _T s(0); + for (size_t k = 0; k < kmax; k++) + { + s += rowi[k] * colj[k]; + } + colj[i] -= s; + rowi[j] = colj[i]; + } + + size_t p = j; + for (size_t i = j + 1; i < _MD; i++) + { + if (std::abs(colj[i]) > std::abs(colj[p])) + p = i; + + } + if (p != j) + { + size_t k = 0; + for (; k < _ND; k++) + { + // We are swapping + _T t = lu(p, k); + lu(p, k) = lu(j, k); + lu(j, k) = t; + } + k = pivotsM[p]; + pivotsM[p] = pivotsM[j]; + pivotsM[j] = k; + } + if (j < _MD && std::abs( lu(j, j) )) + { + for (size_t i = j + 1; i < _MD; i++) + { + // Divide out our rows + lu(i, j) /= lu(j, j); + } + } + + } + + return lu; + } + + /*! + * Permute a matrix from pivots. This funtion does + * not mutate this. + * + * \param pivotsM The M pivots vector + * \param n The number of columns (defaults to this' N) + * \return A copy of this matrix that is permuted + * + * \code + int p[2] = { 1, 0 }; + MatrixMxN<2,2> G = F.permute(P); + * \endcode + * + */ + Like_T permute(const std::vector& pivotsM, size_t n = _ND) const + { + Like_T perm; + for (size_t i = 0; i < _MD; i++) + { + for (size_t j = 0; j < n; j++) + { + perm[i][j] = mRaw[pivotsM[i]][j]; + } + } + return perm; + } + /*! + * Find the L2 norm of the matrix. + * \return The norm + */ + _T norm() const + { + _T acc(0); + for (size_t i = 0; i < _MD; ++i) + { + for (size_t j = 0; j < _ND; ++j) + { + acc += mRaw[i][j] * mRaw[i][j]; + } + } + return (_T)::sqrt((const _T)acc); + } + + /*! + * Scale the entire matrix inplace by the L2 norm value. + * \return A reference to this + */ + MatrixMxN& normalize() + { + return scale(1.0/norm()); + } + + /*! + * Alias for this->add(); + * + * \code + C = A + B; + * \endcode + * + */ + Like_T operator+(const Like_T& mx) const + { + return add(mx); + } + + + /*! + * Alias for this->subtract(); + * + * \code + C = A - B; + * \endcode + * + */ + Like_T operator-(const Like_T& mx) const + { + return subtract(mx); + } + + /*! + * Alias for this->multiply(scalar); + * + * \code + scaled = A * scalar; + * \endcode + * + */ + Like_T operator*(_T scalar) const + { + + return multiply(scalar); + } + + /*! + * Alias for this->multiply(1/scalar); + * + * \code + scaled = A / scalar; + * \endcode + * + */ + Like_T operator/(_T scalar) const + { + + return multiply(1/scalar); + } + + /*! + * Alias for this->multiply(NxP); + * + * \code + C = A * B; + * \endcode + */ + template + MatrixMxN<_MD, _PD, _T> + operator*(const MatrixMxN<_ND, _PD, _T>& mx) const + { + return multiply(mx); + } + + + + +}; + +// A = LU +// A*x = b(piv,:) +// A, x, b + +/*! + * This function creates a matrix of size MxN and type _T + * with a constant value in each element (argument defaults to 0) + * + * This function produces a matrix that is set to this value + * + * \code + MatrixMxN<4, 4> mx = constantMatrix<4, 4, double>(4.2) + * \endcode + * + * This function is relatively worthless, favor the constructor + * + * \param cv An optional constant value + */ +template MatrixMxN<_MD, _ND, _T> + constantMatrix(_T cv = 0) +{ + MatrixMxN<_MD, _ND, _T> mx(cv); + return mx; +} + +/*! + * This function creates an identity matrix of size NxN and type _T + * with 1's in the diagonals. + * + * \code + MatrixMxN<4, 4> = identityMatrix<4, 4, double>(); + * \endcode + * + */ +template MatrixMxN<_ND, _ND, _T> + identityMatrix() +{ + MatrixMxN<_ND, _ND, _T> mx; + for (size_t i = 0; i < _ND; i++) + { + for (size_t j = 0; j < _ND; j++) + { + mx(i, j) = (i == j) ? 1: 0; + } + } + return mx; +} + + +/*! + * Solve Ax = b using LU decomposed matrix and the permutation vector. + * Method based on TNT + * + */ +template + math::linear::MatrixMxN<_ND, _PD, _T> solveLU(const std::vector& pivotsM, + const MatrixMxN<_MD, _ND, _T> &lu, + const MatrixMxN<_ND, _PD, _T> &b) +{ + // If we dont have something in the diagonal, we can't solve this + math::linear::MatrixMxN<_ND, _PD, _T> x = b.permute(pivotsM, _PD); + + for (size_t k = 0; k < _ND; k++) + { + for (size_t i = k + 1; i < _ND; i++) + { + for (size_t j = 0; j < _PD; j++) + { + x(i, j) -= x(k, j)*lu(i, k); + } + } + } + for (sys::SSize_T k = _ND - 1; k >= 0; k--) + { + for (size_t j = 0; j < _PD; j++) + { + x(k, j) /= lu(k, k); + } + + for (sys::SSize_T i = 0; i < k; i++) + { + // This one could be _Q + for (size_t j = 0; j < _PD; j++) + { + x(i, j) -= x(k, j)*lu(i, k); + } + } + } + + return x; +} + +/*! + * Generalized inverse method using LU decomposition + * + * \param mx A matrix to invert + * + * \code + Matrix<3, 3> Ainv = inverseLU<3, double>(A); + * \endcode + * + */ +template inline + MatrixMxN<_ND, _ND, _T> inverseLU(const MatrixMxN<_ND, _ND, _T>& mx) +{ + MatrixMxN<_ND, _ND, _T> a((_T)0); + + // Identity + for (size_t i = 0; i < _ND; i++) + a(i, i) = 1; + + std::vector pivots(_ND); + MatrixMxN<_ND, _ND, _T> lu = mx.decomposeLU(pivots); + + for (size_t i = 0; i < _ND; i++) + { + if ( equals<_T>(lu(i, i), 0) ) + throw except::Exception(Ctxt("Non-invertible matrix!")); + } + + return solveLU<_ND, _ND, _ND, _T>(pivots, lu, a); +} + +/*! + * Generalized inverse function. This function is specialized for 2x2s + * and 3x3s for type double and float. + * + * \code + Matrix<3, 3> Ainv = inverse<3, double>(A); + * \endcode + */ +template inline + MatrixMxN<_ND, _ND, _T> inverse(const MatrixMxN<_ND, _ND, _T>& mx) +{ + return inverseLU<_ND, _T>(mx); +} + +/*! + * Full specialization for 2x2 matrices. Way faster than + * doing the generalized inverse. This function just magically + * gets called if you try to invert a 2x2 double matrix (you + * dont have to do anything different than usual) + * + * \param mx A 2x2 double matrix + * \return A 2x2 double matrix + * + */ +template<> inline + MatrixMxN<2, 2, double> inverse<2, double>(const MatrixMxN<2, 2, double>& mx); + + +template<> inline + MatrixMxN<3, 3, double> inverse<3, double>(const MatrixMxN<3, 3, double>& mx); + +template<> inline + MatrixMxN<2, 2, float> inverse<2, float>(const MatrixMxN<2, 2, float>& mx); + + +template<> inline + MatrixMxN<3, 3, float> inverse<3, float>(const MatrixMxN<3, 3, float>& mx); + + +} +} + + +template<> inline +math::linear::MatrixMxN<2, 2, double> +math::linear::inverse<2, double>(const math::linear::MatrixMxN<2, 2, double>& mx) +{ + math::linear::MatrixMxN<2, 2, double> inv; + double determinant = mx[1][1] * mx[0][0] - mx[1][0]*mx[0][1]; + + if (equals(determinant, 0.0)) + throw except::Exception(Ctxt("Non-invertible matrix!")); + + // Standard 2x2 inverse + inv[0][0] = mx[1][1]; + inv[0][1] = -mx[0][1]; + inv[1][0] = -mx[1][0]; + inv[1][1] = mx[0][0]; + + inv.scale( 1.0 / determinant ); + return inv; +} + +template<> inline +math::linear::MatrixMxN<3, 3, double> +math::linear::inverse<3, double>(const math::linear::MatrixMxN<3, 3, double>& mx) +{ + math::linear::MatrixMxN<3, 3> inv; + + double a = mx[0][0]; + double b = mx[0][1]; + double c = mx[0][2]; + + double d = mx[1][0]; + double e = mx[1][1]; + double f = mx[1][2]; + + double g = mx[2][0]; + double h = mx[2][1]; + double i = mx[2][2]; + + double g1 = e*i - f*h; + double g2 = d*i - f*g; + double g3 = d*h - e*g; + + double determinant = + a*g1 - b*g2 + c*g3; + + if (math::linear::equals(determinant, 0.0)) + throw except::Exception(Ctxt("Non-invertible matrix!")); + + + inv[0][0] = g1; inv[0][1] = c*h - b*i; inv[0][2] = b*f - c*e; + inv[1][0] = -g2; inv[1][1] = a*i - c*g; inv[1][2] = c*d - a*f; + inv[2][0] = g3; inv[2][1] = b*g - a*h; inv[2][2] = a*e - b*d; + inv.scale( 1.0 / determinant ); + + return inv; + +} + + +template<> inline +math::linear::MatrixMxN<2, 2, float> +math::linear::inverse<2, float>(const math::linear::MatrixMxN<2, 2, float>& mx) +{ + math::linear::MatrixMxN<2, 2, float> inv; + float determinant = mx[1][1] * mx[0][0] - mx[1][0]*mx[0][1]; + + if (math::linear::equals(determinant, 0.0f)) + throw except::Exception(Ctxt("Non-invertible matrix!")); + + // Standard 2x2 inverse + inv[0][0] = mx[1][1]; + inv[0][1] = -mx[0][1]; + inv[1][0] = -mx[1][0]; + inv[1][1] = mx[0][0]; + + inv.scale( 1.0f / determinant ); + return inv; +} + +template<> inline +math::linear::MatrixMxN<3, 3, float> +math::linear::inverse<3, float>(const math::linear::MatrixMxN<3, 3, float>& mx) +{ + math::linear::MatrixMxN<3, 3, float> inv; + + float a = mx[0][0]; + float b = mx[0][1]; + float c = mx[0][2]; + + float d = mx[1][0]; + float e = mx[1][1]; + float f = mx[1][2]; + + float g = mx[2][0]; + float h = mx[2][1]; + float i = mx[2][2]; + + float g1 = e*i - f*h; + float g2 = d*i - f*g; + float g3 = d*h - e*g; + + float determinant = + a*g1 - b*g2 + c*g3; + + if (equals(determinant, 0.0f)) + throw except::Exception(Ctxt("Non-invertible matrix!")); + + + inv[0][0] = g1; inv[0][1] = c*h - b*i; inv[0][2] = b*f - c*e; + inv[1][0] = -g2; inv[1][1] = a*i - c*g; inv[1][2] = c*d - a*f; + inv[2][0] = g3; inv[2][1] = b*g - a*h; inv[2][2] = a*e - b*d; + inv.scale( 1.0f / determinant ); + + return inv; + +} + + +/*! + * Could possibly be more clever here, and template the actual matrix + */ +template math::linear::MatrixMxN<_MD, _ND, _T> + operator*(_T scalar, const math::linear::MatrixMxN<_MD, _ND, _T>& m) +{ + return m.multiply(scalar); +} + + +/*! + * This method "cleans" a Matrix of unknown type. Concrete instantiations could + * include MatrixMxN or Matrix2D, or any other type that has a rows() and cols(), + * a proper assignment operator from the same type, and an overloaded (i, j) + * operator. + * + * Any value that is within the given epsilon of an integer is rounded to that + * integer value. The parameter is unmodified + * + * \param constMatrix A matrix to tidy + * \param The epsilon fudge factor + * \return + */ +template Matrix_T tidy(const Matrix_T& constMatrix, + double eps = std::numeric_limits::epsilon()) +{ + Matrix_T mx = constMatrix; + for (size_t i = 0; i < mx.rows(); i++) + { + for (size_t j = 0; j < mx.cols(); j++) + { + double lower = std::floor(mx(i,j)); + double higher = std::ceil(mx(i,j)); + + // If the floor is within epsilon, floor this + if (math::linear::equals(std::abs(mx(i, j) - lower), 0.0, eps)) + mx(i, j) = lower; + + else if (math::linear::equals(std::abs(higher - mx(i, j)), 0.0, eps)) + mx(i, j) = higher; + + if (mx(i, j) == -0) + mx(i, j) = 0; + } + } + return mx; +} + +/*! + * Try to pretty print the Matrix to an ostream. + * \return Reference to ostream + */ +template + std::ostream& operator<<(std::ostream& os, + const math::linear::MatrixMxN<_MD, _ND, _T>& m) +{ + + + size_t i, j; + os << "(" << _MD << ',' << _ND << ")" << std::endl; + + for (i = 0; i < _MD; ++i) + { + for (j = 0; j < _ND; ++j) + { + os << std::setw(10) << m(i, j) << " "; + } + os << std::endl; + } + + + return os; +} + + +#endif diff --git a/modules/c++/math.linear/include/math/linear/Vector.h b/modules/c++/math.linear/include/math/linear/Vector.h new file mode 100644 index 000000000..cd4019aa6 --- /dev/null +++ b/modules/c++/math.linear/include/math/linear/Vector.h @@ -0,0 +1,454 @@ +/* ========================================================================= + * This file is part of math.linear-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * math.linear-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ +#ifndef __MATH_LINEAR_VECTOR_H__ +#define __MATH_LINEAR_VECTOR_H__ + +#include "math/linear/Matrix2D.h" + +namespace math +{ +namespace linear +{ + +/*! + * \class Vector + * \brief Flexible size vector implementation + * + * This class provides a resizable, non-fixed implementation + * of a vector. It shares most functionality with VectorN + * but VectorN should always be preferred whenever the sizes + * are known at compile time. + * + * This class implementation is also borrowed from VectorN + * where possible - the internal representation is still + * a single (2D) column vector represented as a matrix. + * + */ +template class Vector +{ + Matrix2D<_T> mRaw; +public: + + //! Default constructor (no initialization) + Vector() {} + + /*! + * Create a vector of given size, each component + * initialized to a single value + * + * \param sz The size of the Vector + * \param sv The scalar value to assign from + */ + Vector(size_t sz, _T sv = 0.0) + { + mRaw = Matrix2D<_T>(sz, 1, sv); + } + + /*! + * Create a vector of given size from a raw + * pointer (which must be pointing at an array + * that is at least as large as the size argument + * + * \param sz The size of the Vector + * \param raw A raw array of values to assign + */ + Vector(size_t sz, const _T* raw) + { + mRaw = Matrix2D<_T>(sz, 1, raw); + } + + /*! + * Copy the contents from one Vector + * to another. + * + * \param v The vector to assign from + */ + Vector(const Vector& v) + { + mRaw = v.mRaw; + } + + /*! + * Copy the contents from a std::vector + * into our Vector object + * + * \param v The vector to assign from + */ + Vector(const std::vector<_T>& v) + { + mRaw = Matrix2D<_T>(v.size(), 1, v); + } + + /*! + * Copy the contents of a Matrix into + * memory. This effectively will + * reshape the matrix into a single column + * vector. For single column or single row + * matrices, the Vector will become a single + * column vector Matrix + * + * \param mx A matrix to copy from + */ + Vector(const Matrix2D<_T>& mx) + { + mRaw = Matrix2D<_T>(mx.size(), 1, mx.mRaw); + } + + /*! + * Copy the contents from one Vector + * to another. + * + * \param v The vector to assign from + * \return A reference + */ + Vector& operator=(const Vector& v) + { + if (this != &v) + { + mRaw = v.mRaw; + } + return *this; + } + + /*! + * Copy the contents of a Matrix into + * memory. This effectively will + * reshape the matrix into a single column + * vector. For single column or single row + * matrices, the Vector will become a single + * column vector Matrix + * + * \param mx A matrix to copy from + * \param A reference + */ + Vector& operator=(const Matrix2D<_T>& mx) + { + mRaw = Matrix2D<_T>(mx.size(), 1, mx.mRaw); + return *this; + } + + /*! + * Create a vector of size 1 with a + * single value specified. + * + * \param sv The scalar value to assign from + * \return The vector + */ + Vector& operator=(const _T& sv) + { + mRaw = sv; + return *this; + } + + /*! + * Copy the contents from a std::vector + * into our Vector object + * + * \param v The vector to assign from + * \return A reference + */ + Vector& operator=(const std::vector<_T>& v) + { + mRaw = Matrix2D<_T>(v.size(), 1, v); + return *this; + } + + + //! Destructor + ~Vector() {} + + /*! + * Get the number of components in the vector + * \return size + */ + size_t size() const { return mRaw.size(); } + + //! Get back the raw matrix implementation + Matrix2D<_T>& matrix() { return mRaw; } + + //! Get back the const raw matrix implementation + const Matrix2D<_T>& matrix() const { return mRaw; } + + //! Get back a const-vector + const _T* get() const { return mRaw.get(); } + + //! Const dereference operator + inline _T operator[](size_t i) const + { +#if defined(MATH_LINEAR_BOUNDS) + assert( i < _ND ); +#endif + return mRaw.get()[i]; + } + + //! Non-const reference operator + inline _T& operator[](size_t i) + { +#if defined(MATH_LINEAR_BOUNDS) + assert( i < _ND ); +#endif + return mRaw.mRaw[i]; + + } + + /*! + * Compute the dot product between + * two vectors of equal size. This + * method could just call the matrix + * multiply, though this method is more + * efficient. + * + * \param vec Vector to dot with + * \return The magnitude + */ + _T dot(const Vector& vec_) const + { + _T acc(0); + size_t sz = mRaw.size(); + if (vec_.size() != sz) + throw except::Exception(Ctxt("Dot product requires equal size vectors")); + for (size_t i = 0; i < sz; ++i) + { + acc += vec_[i] * mRaw.mRaw[i]; + } + return acc; + } + + /*! + * Euclidean, L2 norm + */ + _T norm() const + { + + return mRaw.norm(); + } + + //! Normalize a value + void normalize() + { + mRaw.normalize(); + } + + //! Scale a value + void scale(_T scalar) + { + mRaw.scale(scalar); + } + + //! Add this to another vector + Vector& + operator+=(const Vector& v) + { + mRaw += v.matrix(); + return *this; + } + + //! Subtract another vector from this + Vector& + operator-=(const Vector& v) + { + mRaw -= v.matrix(); + return *this; + } + + //! Add this to another vector and return a copy + Vector add(const Vector& v) const + { + Vector v2(*this); + v2 += v; + return v2; + } + + //! Subtract this from another vector and return a copy + Vector subtract(const Vector& v) const + { + Vector v2(*this); + v2 -= v; + return v2; + } + + //! Overloaded plus operator + Vector + operator+(const Vector& v) const + { + return add(v); + } + + //! Overloaded minus operator + Vector + operator-(const Vector& v) const + { + return subtract(v); + } + + //! Element-wise multiply assign from another vector + Vector& operator *=(const Vector& v) + { + size_t N = size(); + for (unsigned int i = 0; i < N; i++) + { + mRaw.mRaw[i] *= v.mRaw.mRaw[i]; + } + return *this; + + } + + //! Scalar value multiply assignment + Vector& operator *=(_T sv) + { + scale(sv); + return *this; + + } + + //! Scalar value assignment + Vector operator *(_T sv) const + { + + Vector v2(*this); + v2 *= sv; + return v2; + + } + + /*! + * Divide another vector. This doesnt mean much + * geometrically by itself, but is handy for + * many equations + */ + Vector& operator /=(const Vector& v) + { + size_t sz = size(); + for (size_t i = 0; i < sz; i++) + { + mRaw.mRaw[i] /= v.mRaw.mRaw[i]; + } + return *this; + } + + /* + * Multiply another vector and produce a + * copy + */ + Vector operator*(const Vector& v) const + { + Vector v2(*this); + v2 *= v; + return v2; + } + + //! Divide anotehr vector into this and product a copy + Vector operator/(const Vector& v) const + { + Vector v2(*this); + v2 /= v; + return v2; + } + + /*! + * Flexible templated equality operator. This allows + * comparisons of types other than just Vectors + * including fixed type VectorN and std::vector + */ + template bool operator==(const Vector_T& v) const + { + size_t sz = v.size(); + for (size_t i = 0; i < sz; ++i) + if (!equals<_T>((*this)[i], v[i])) + return false; + + return true; + } + + //! Negate the equality operator + template bool operator!=(const Vector_T& v) const + { + return !(*this == v); + } + +}; + +/*! + * Cross product of two 3-dimensional vectors. + * You should never ever use this, Vector's are + * MUCH slower than VectorN's + */ +template Vector<_T> cross(const Vector<_T>& u, + const Vector<_T>& v) +{ + Vector<_T> xp(3); + xp[0] = (u[1]*v[2] - u[2]*v[1]); + xp[1] = (u[2]*v[0] - u[0]*v[2]); + xp[2] = (u[0]*v[1] - u[1]*v[0]); + return xp; +} + +//! Fairly non-useful method, retained for backwards compatibility +template Vector<_T> + constantVector(size_t sz, _T cv = 0) +{ + Vector<_T> v(sz, cv); + return v; +} + +} +} + +/*! + * Matrix-vector multiplication. Produces + * a vector object. + */ + +template + math::linear::Vector<_T> + operator*(const math::linear::Matrix2D<_T>& m, + const math::linear::Vector<_T>& v) +{ + return math::linear::Vector<_T>(m * v.matrix()); +} + +/*! + * Reverse order template overload for scalar * Vector + */ +template math::linear::Vector<_T> + operator*(_T scalar, const math::linear::Vector<_T>& v) +{ + return v * scalar; +} + + +/*! + * Pretty(?)-print vector + */ +template + std::ostream& operator<<(std::ostream& os, + const math::linear::Vector<_T>& v) +{ + for (size_t i = 0; i < v.size(); ++i) + { + os << std::setw(10) << v[i] << " "; + } + return os; + +} + +#endif diff --git a/modules/c++/math.linear/include/math/linear/VectorN.h b/modules/c++/math.linear/include/math/linear/VectorN.h new file mode 100644 index 000000000..eb0971461 --- /dev/null +++ b/modules/c++/math.linear/include/math/linear/VectorN.h @@ -0,0 +1,367 @@ +/* ========================================================================= + * This file is part of math.linear-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * math.linear-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ +#ifndef __MATH_LINEAR_VECTOR_N_H__ +#define __MATH_LINEAR_VECTOR_N_H__ + +#include "math/linear/MatrixMxN.h" + +namespace math +{ +namespace linear +{ + + +template class VectorN +{ + typedef VectorN<_ND, _T> Like_T; + MatrixMxN<_ND, 1, _T> mRaw; + +public: + + + //! Default constructor (no initialization) + VectorN() {} + + /*! + * Create a vector of fixed size (_ND), each component + * initialized to a single value + * + * \param sv The scalar value to assign from + */ + VectorN(_T sv) + { + mRaw = sv; + } + + /*! + * Vector copy from a _T pointer. + * This is not a pointer reference! + * + * \param raw A raw pointer + * + */ + VectorN(const _T* raw) + { + mRaw = raw; + } + + /*! + * Copy a vector from another vector + * + */ + VectorN(const VectorN& v) + { + mRaw = v.mRaw; + } + + /*! + * Initialize from a one dimensional + * row vector matrix + */ + VectorN(const MatrixMxN<_ND, 1, _T>& mx) + { + mRaw = mx; + } + /*! + * Copy a vector from a raw STL vector + * which must be sized with at least _ND + * elements (the rest will be ignored) + * + */ + VectorN(const std::vector<_T>& raw) + { + if (raw.size() < _ND) + throw except::Exception(Ctxt("Not enough elements")); + + mRaw = raw; + } + + /*! + * Copy from a standard STL vector of size + * greater or equal to _ND (the rest will + * be ignored). + * + * \param raw A vector + */ + VectorN& operator=(const std::vector<_T>& raw) + { + if (raw.size() < _ND) + throw except::Exception(Ctxt("Not enough elements")); + + mRaw = raw; + return *this; + } + + /*! + * Construct a VectorN from a raw pointer + * where the raw pointer is expected to + * point to an array with at least _ND + * elements + * + * \param raw A raw pointer + */ + VectorN& operator=(const _T* raw) + { + mRaw = raw; + return *this; + } + + /*! + * Assignment operator from a VectorN + */ + VectorN& operator=(const VectorN& v) + { + if (this != &v) + { + mRaw = v.mRaw; + } + return *this; + } + + /*! + * Assign a single scalar value into + * every component of this VectorN + * + * \param sv Scalar value + * \return A reference + */ + VectorN& operator=(const _T& sv) + { + mRaw = sv; + return *this; + } + + VectorN& operator=(const MatrixMxN<_ND, 1, _T>& mx) + { + mRaw = mx; + return *this; + } + + //! Destructor + ~VectorN() {} + + + + + MatrixMxN<_ND, 1, _T>& matrix() { return mRaw; } + const MatrixMxN<_ND, 1, _T>& matrix() const { return mRaw; } + + inline _T operator[](size_t i) const + { +#if defined(MATH_LINEAR_BOUNDS) + assert( i < _ND ); +#endif + return mRaw[i][0]; + } + inline _T& operator[](size_t i) + { +#if defined(MATH_LINEAR_BOUNDS) + assert( i < _ND ); +#endif + return mRaw[i][0]; + + } + + inline size_t size() const { return _ND; } + + _T dot(const VectorN<_ND>& vec) const + { + _T acc(0); + for (size_t i = 0; i < _ND; ++i) + { + acc += (*this)[i] * vec[i]; + } + return acc; + } + + /*! + * Euclidean, L2 norm + */ + _T norm() const + { + return mRaw.norm(); + } + + void normalize() + { + mRaw.normalize(); + } + + void scale(_T scalar) + { + mRaw.scale(scalar); + } + + Like_T& + operator+=(const Like_T& v) + { + mRaw += v.matrix(); + return *this; + } + Like_T& + operator-=(const Like_T& v) + { + mRaw -= v.matrix(); + return *this; + } + + Like_T add(const Like_T& v) const + { + Like_T v2(*this); + v2 += v; + return v2; + } + + Like_T subtract(const Like_T& v) const + { + Like_T v2(*this); + v2 -= v; + return v2; + } + + Like_T + operator+(const Like_T& v) const + { + return add(v); + } + Like_T + operator-(const Like_T& v) const + { + return subtract(v); + } + + Like_T& operator *=(const Like_T& v) + { + for (size_t i = 0; i < _ND; i++) + { + mRaw(i, 0) *= v[i]; + } + return *this; + + } + + Like_T& operator *=(_T sv) + { + scale(sv); + return *this; + + } + + Like_T operator *(_T sv) const + { + + Like_T v2(*this); + v2 *= sv; + return v2; + + } + + + Like_T& operator /=(const Like_T& v) + { + for (size_t i = 0; i < _ND; i++) + { + mRaw(i, 0) /= v[i]; + } + return *this; + } + + Like_T operator*(const Like_T& v) const + { + Like_T v2(*this); + v2 *= v; + return v2; + } + + Like_T operator/(const Like_T& v) const + { + Like_T v2(*this); + v2 /= v; + return v2; + } + + template bool operator==(const Vector_T& v) const + { + size_t sz = v.size(); + for (size_t i = 0; i < sz; ++i) + if (!equals<_T>((*this)[i], v[i])) + return false; + + + return true; + } + + template bool operator!=(const Vector_T& v) const + { + return !(*this == v); + } + +}; + +template VectorN<3, _T> cross(const VectorN<3, _T>& u, + const VectorN<3, _T>& v) +{ + VectorN<3, _T> xp; + xp[0] = (u[1]*v[2] - u[2]*v[1]); + xp[1] = (u[2]*v[0] - u[0]*v[2]); + xp[2] = (u[0]*v[1] - u[1]*v[0]); + return xp; +} + +template VectorN<_ND, _T> + constantVector(_T cv = 0) +{ + VectorN<_ND, _T> v(constantMatrix<_ND, 1, _T>(cv)); + return v; +} + +} +} + +template + math::linear::VectorN<_MD, _T> + operator*(const math::linear::MatrixMxN<_MD, _ND, _T>& m, + const math::linear::VectorN<_ND, _T>& v) +{ + return math::linear::VectorN<_MD, _T>(m * v.matrix()); +} + +template math::linear::VectorN<_ND, _T> + operator*(_T scalar, const math::linear::VectorN<_ND, _T>& v) +{ + return v * scalar; +} + + +template + std::ostream& operator<<(std::ostream& os, + const math::linear::VectorN<_ND, _T>& v) +{ + for (size_t i = 0; i < _ND; ++i) + { + os << std::setw(10) << v[i] << " "; + } + return os; + +} + +#endif diff --git a/modules/c++/math.linear/tests/test_cx.cpp b/modules/c++/math.linear/tests/test_cx.cpp new file mode 100644 index 000000000..054e9eff4 --- /dev/null +++ b/modules/c++/math.linear/tests/test_cx.cpp @@ -0,0 +1,99 @@ +/* ========================================================================= + * This file is part of math.linear-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * math.linear-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ +#include + +namespace mx=math::linear; + +typedef std::complex _Cf; +typedef mx::MatrixMxN<2, 2, _Cf> _2x2; +typedef mx::MatrixMxN<3, 2, _Cf> _3x2; +typedef mx::MatrixMxN<3, 3, _Cf> _3x3; +typedef mx::MatrixMxN<4, 4, _Cf> _4x4; +typedef mx::VectorN<3, _Cf> _V3; +typedef mx::VectorN<2, _Cf> _V2; + +int main() +{ + _3x3 A = mx::identityMatrix<3, _Cf>(); + std::cout << A << std::endl; + + //_Cf cf12(1.2); + _V3 v3 = mx::constantVector<3, _Cf>(1.2); + + //_Cf cf2(2); + v3[2] = 2; //cf2; + + std::cout << A * v3 << std::endl; + + + std::cout << v3 + v3 << std::endl; + +// v3.normalize(); +// std::cout << v3 << std::endl; +// std::cout << v3.norm() << std::endl; + + std::cout << v3 * 4.0 << std::endl; + + // {1, 0, 0} + v3 = mx::constantVector<3, _Cf>(0); + v3[0] = 1; + + // {0, 1, 0} + _V3 y = mx::constantVector<3, _Cf>(0); + y[1] = 1; + + std::cout << cross(v3, y) << std::endl; + + // PA = LU + const unsigned int seed = + static_cast(sys::LocalDateTime().getTimeInMillis()); + ::srand(seed); + A(0, 0) = _Cf((float)rand()/RAND_MAX, (float)rand()/RAND_MAX); + A(0, 1) = _Cf((float)rand()/RAND_MAX, (float)rand()/RAND_MAX); + A(0, 2) = _Cf((float)rand()/RAND_MAX, (float)rand()/RAND_MAX); + A(1, 0) = _Cf((float)rand()/RAND_MAX, (float)rand()/RAND_MAX); + A(1, 1) = _Cf((float)rand()/RAND_MAX, (float)rand()/RAND_MAX); + A(1, 2) = _Cf((float)rand()/RAND_MAX, (float)rand()/RAND_MAX); + A(2, 0) = _Cf((float)rand()/RAND_MAX, (float)rand()/RAND_MAX); + A(2, 1) = _Cf((float)rand()/RAND_MAX, (float)rand()/RAND_MAX); + A(2, 2) = _Cf((float)rand()/RAND_MAX, (float)rand()/RAND_MAX); + A.scale(10); + + std::cout << "A: " << A << std::endl; + + std::vector p; + p.resize(3); + _3x3 lu = A.decomposeLU(p); + _3x3 PA = A.permute(p); + + _3x3 L = mx::identityMatrix<3, _Cf>(); + _3x3 U = mx::identityMatrix<3, _Cf>(); + + U(0, 0) = lu(0, 0); U(0, 1) = lu(0, 1); U(0, 2) = lu(0, 2); + L(1, 0) = lu(1, 0); U(1, 1) = lu(1, 1); U(1, 2) = lu(1, 2); + L(2, 0) = lu(2, 0); L(2, 1) = lu(2, 1); U(2, 2) = lu(2, 2); + + std::cout << "L: " << L << std::endl; + std::cout << "U: " << U << std::endl; + std::cout << "LU: " << L * U << std::endl; + std::cout << "PA: " << PA << std::endl; +} diff --git a/modules/c++/math.linear/tests/test_diag.cpp b/modules/c++/math.linear/tests/test_diag.cpp new file mode 100644 index 000000000..24ca1b36d --- /dev/null +++ b/modules/c++/math.linear/tests/test_diag.cpp @@ -0,0 +1,63 @@ +/* ========================================================================= + * This file is part of math.linear-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * math.linear-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ +#include + +namespace mx=math::linear; + +typedef mx::MatrixMxN<2, 2> _2x2; +typedef mx::MatrixMxN<3, 2> _3x2; +typedef mx::MatrixMxN<3, 3> _3x3; +typedef mx::MatrixMxN<4, 4> _4x4; + + +int main() +{ + _2x2 B = mx::identityMatrix<2, double>(); + B(0, 0) = 1.1; + std::cout << "B: " << B << std::endl; + + _3x2 A(0.0); + + A(0, 0) = 1; A(1, 0) = 3; A(2, 0) = 5; + A(0, 1) = 2; A(1, 1) = 4; A(2, 1) = 6; + + std::cout << "A: " << A << std::endl; + + _3x2 C = A.multiplyDiagonal(B); + + /* + + >> B = [1.1 0; 0 1.0]; + >> A = [1 2; 3 4; 5 6]; + >> C = A * B + + C = + + 1.1000 2.0000 + 3.3000 4.0000 + 5.5000 6.0000 + + */ + std::cout << "C: " << C << std::endl; + + +} diff --git a/modules/c++/math.linear/unittests/test_Vector.cpp b/modules/c++/math.linear/unittests/test_Vector.cpp new file mode 100644 index 000000000..7162a538b --- /dev/null +++ b/modules/c++/math.linear/unittests/test_Vector.cpp @@ -0,0 +1,458 @@ +#include +#include "TestCase.h" +#include "math/linear/Vector.h" + +using namespace math::linear; +using namespace std; + + +TEST_CASE(testDefaultConstructor) +{ + Vector v; + TEST_ASSERT_EQ(v.size(), 0); +} + + +TEST_CASE(testScalarConstructor) +{ + Vector v(3, 42); + TEST_ASSERT_EQ(v.size(), 3); + TEST_ASSERT_EQ(v[0], 42); + TEST_ASSERT_EQ(v[1], 42); + TEST_ASSERT_EQ(v[2], 42); + // check for subscript out of bounds? +} + + +TEST_CASE(testRawConstructor) +{ + double raw[] = {1,2,3}; + Vector v(3, raw); + TEST_ASSERT_EQ(v.size(), 3); + TEST_ASSERT_EQ(v[0], 1); + TEST_ASSERT_EQ(v[1], 2); + TEST_ASSERT_EQ(v[2], 3); +} + + +TEST_CASE(testCopyConstructor) +{ + Vector vsrc(3); + vsrc[0] = 1; + vsrc[1] = 2; + vsrc[2] = 3; + Vector v(vsrc); + TEST_ASSERT_EQ(v.size(), 3); + TEST_ASSERT_EQ(v[0], vsrc[0]); + TEST_ASSERT_EQ(v[1], vsrc[1]); + TEST_ASSERT_EQ(v[2], vsrc[2]); + + vsrc[0] = -1; + TEST_ASSERT_EQ(vsrc[0], -1); // should change + TEST_ASSERT_EQ(v[0], 1); // shouldn't change +} + + +TEST_CASE(testStdVectorConstructor) +{ + std::vector stdvec; + stdvec.push_back(10); + stdvec.push_back(11); + stdvec.push_back(12); + + Vector v(stdvec); + TEST_ASSERT_EQ(v.size(), 3); + TEST_ASSERT_EQ(v[0], stdvec[0]); + TEST_ASSERT_EQ(v[1], stdvec[1]); + TEST_ASSERT_EQ(v[2], stdvec[2]); + + stdvec[0] *= -1; + stdvec[1] *= -1; + stdvec[2] *= -1; + + TEST_ASSERT_EQ(v[0], 10); + TEST_ASSERT_EQ(v[1], 11); + TEST_ASSERT_EQ(v[2], 12); +} + + +TEST_CASE(testAssignmentOperator) +{ + Vector vsrc(2); + vsrc[0] = 42; + vsrc[1] = 99; + Vector v; + v = vsrc; + TEST_ASSERT_EQ(v.size(), 2); + TEST_ASSERT_EQ(v[0], 42); + TEST_ASSERT_EQ(v[1], 99); + // TODO: What if I change the length of v5? Does v7 remain unchanged (length & content)? +} + + +TEST_CASE(testScalarAssignment) +{ + Vector v(5, 123.456); + TEST_ASSERT_EQ(v.size(), 5); + for (int i = 0; i < 5; i++) + TEST_ASSERT_EQ(v[i], 123.456); + + v = 99; + TEST_ASSERT_EQ(v.size(), 1); + TEST_ASSERT_EQ(v[0], 99); +} + + +TEST_CASE(testStdVectorAssignment) +{ + std::vector stdvec; + stdvec.push_back(10); + stdvec.push_back(11); + stdvec.push_back(12); + + Vector v(20, -1); + v = stdvec; + TEST_ASSERT_EQ(v.size(), 3); + TEST_ASSERT_EQ(v[0], 10); + TEST_ASSERT_EQ(v[1], 11); + TEST_ASSERT_EQ(v[2], 12); +} + + +TEST_CASE(testDotProduct) +{ + Vector vd1(5, 2); + Vector vd2(5, 3); + const double dotprod(vd1.dot(vd2)); + TEST_ASSERT_EQ(dotprod, 2*3*5); + + bool threw(false); + try + { + Vector wrongSize(2); + vd1.dot(wrongSize); + } + catch(...) + { + threw = true; + } + TEST_ASSERT(threw); +} + + +TEST_CASE(testNorm) +{ + std::vector stdvec; + stdvec.push_back(10); + stdvec.push_back(11); + stdvec.push_back(12); + Vector vnorm1(stdvec); + const double norm(vnorm1.norm()); + const double arg(10.*10 + 11.*11 + 12.*12); + const double expectedValue(::sqrt(arg)); + TEST_ASSERT_EQ(norm, expectedValue); +} + + +TEST_CASE(testNormalize) +{ + Vector vnorm(4, 4.0); + vnorm.normalize(); + TEST_ASSERT_EQ(vnorm[0], 0.5); + TEST_ASSERT_EQ(vnorm[1], 0.5); + TEST_ASSERT_EQ(vnorm[2], 0.5); + TEST_ASSERT_EQ(vnorm[3], 0.5); +} + + +TEST_CASE(testScale) +{ + Vector vscale(2,4.0); + vscale.scale(1.0 / 4.0); + TEST_ASSERT_EQ(vscale[0], 1.0); + TEST_ASSERT_EQ(vscale[1], 1.0); +} + + +TEST_CASE(testOperatorPlusEquals) +{ + Vector v1(3, 1); + Vector v2(3, -1); + + v2 += v1; + + TEST_ASSERT_EQ(v1.size(), 3); + TEST_ASSERT_EQ(v2.size(), 3); + + TEST_ASSERT_EQ(v2[0], 0); + TEST_ASSERT_EQ(v2[1], 0); + TEST_ASSERT_EQ(v2[2], 0); + + TEST_ASSERT_EQ(v1[0], 1); + TEST_ASSERT_EQ(v1[1], 1); + TEST_ASSERT_EQ(v1[2], 1); +} + + +TEST_CASE(testOperatorPlus) +{ + Vector v1(3, 42); + Vector v2(3, 11); + Vector v3; + + v3 = v1 + v2; + + TEST_ASSERT_EQ(v1.size(), 3); + TEST_ASSERT_EQ(v2.size(), 3); + TEST_ASSERT_EQ(v3.size(), 3); + + TEST_ASSERT_EQ(v1[0], 42); + TEST_ASSERT_EQ(v1[1], 42); + TEST_ASSERT_EQ(v1[2], 42); + + TEST_ASSERT_EQ(v2[0], 11); + TEST_ASSERT_EQ(v2[1], 11); + TEST_ASSERT_EQ(v2[2], 11); + + TEST_ASSERT_EQ(v3[0], 53); + TEST_ASSERT_EQ(v3[1], 53); + TEST_ASSERT_EQ(v3[2], 53); +} + + +TEST_CASE(testOperatorMinusEquals) +{ + //TODO: Vector& operator-=(const Vector& v) + Vector v1(5, 13); + Vector v2(5, -5); + + v2 -= v1; + TEST_ASSERT_EQ(v1.size(), 5); + TEST_ASSERT_EQ(v2.size(), 5); + for (int i = 0; i < 5; i++) + TEST_ASSERT_EQ(v2[i], -18); + for (int i = 0; i < 5; i++) + TEST_ASSERT_EQ(v1[i], 13); +} + + +TEST_CASE(testAdd) +{ + Vector v1(3, 2.4); + Vector v2(3, 1.4); + + // TODO: Test what happens if v1 & v2 are of different lengths. + Vector v3(v2.add(v1)); + + TEST_ASSERT_EQ(v1.size(), 3); + TEST_ASSERT_EQ(v2.size(), 3); + TEST_ASSERT_EQ(v3.size(), 3); + + TEST_ASSERT_EQ(v1[0], 2.4); + TEST_ASSERT_EQ(v1[1], 2.4); + TEST_ASSERT_EQ(v1[2], 2.4); + + TEST_ASSERT_EQ(v2[0], 1.4); + TEST_ASSERT_EQ(v2[1], 1.4); + TEST_ASSERT_EQ(v2[2], 1.4); + + TEST_ASSERT_EQ(v3[0], 3.8); + TEST_ASSERT_EQ(v3[1], 3.8); + TEST_ASSERT_EQ(v3[2], 3.8); +} + + +TEST_CASE(testSubtract) +{ + Vector v1(3, 2.4); + Vector v2(3, 1.4); + + // TODO: Test what happens if v1 & v2 are of different lengths. + Vector v3(v2.subtract(v1)); + + TEST_ASSERT_EQ(v1.size(), 3); + TEST_ASSERT_EQ(v2.size(), 3); + TEST_ASSERT_EQ(v3.size(), 3); + + TEST_ASSERT_EQ(v1[0], 2.4); + TEST_ASSERT_EQ(v1[1], 2.4); + TEST_ASSERT_EQ(v1[2], 2.4); + + TEST_ASSERT_EQ(v2[0], 1.4); + TEST_ASSERT_EQ(v2[1], 1.4); + TEST_ASSERT_EQ(v2[2], 1.4); + + TEST_ASSERT_EQ(v3[0], -1); + TEST_ASSERT_EQ(v3[1], -1); + TEST_ASSERT_EQ(v3[2], -1); +} + + +TEST_CASE(testOperatorMinus) +{ + Vector v1(4), v2(4); + for (int i = 0; i < 4; i++) + { + v1[i] = i; + v2[i] = -i; + } + Vector v3(v2 - v1); + // TODO: Test what happens if v1 & v2 are of different lengths. + + TEST_ASSERT_EQ(v1.size(), 4); + TEST_ASSERT_EQ(v2.size(), 4); + TEST_ASSERT_EQ(v3.size(), 4); + + for (int i = 0; i < 4; i++) + { + TEST_ASSERT_EQ(v1[i], i); + TEST_ASSERT_EQ(v2[i], -i); + } + + for (int i = 0; i < 4; i++) + TEST_ASSERT_EQ(v3[i], -2 * i); +} + + +TEST_CASE(testOperatorTimesEquals) +{ + Vector v1(4); + for (int i = 0; i < 4; i++) + v1[i] = i; + Vector v2(4); + for (int i = 0; i < 4; i++) + v2[i] = -i; + + v2 *= v1; + + for (int i = 0; i < 4; i++) + TEST_ASSERT_EQ(v1[i], i); + for (int i = 0; i < 4; i++) + TEST_ASSERT_EQ(v2[i], -i * i); + + // TODO: Test what happens if v1 & v2 are of different lengths. +} + + +TEST_CASE(testOperatorTimesEqualsScalar) +{ + Vector v1(5); + for (int i = 0; i < 5; i++) + v1[i] = i; + + v1 *= 3; + + for (int i = 0; i < 5; i++) + TEST_ASSERT_EQ(v1[i], 3 * i); +} + + +TEST_CASE(testOperatorTimesScalar) +{ + Vector v1(5); + for (int i = 0; i < 5; i++) + v1[i] = i; + + Vector v2(v1 * 2); + + for (int i = 0; i < 5; i++) + TEST_ASSERT_EQ(v1[i], i); + for (int i = 0; i < 5; i++) + TEST_ASSERT_EQ(v2[i], 2 * i); +} + +TEST_CASE(testElementDivision) +{ + Vector numerator(3); + numerator[0] = 0; + numerator[1] = 1; + numerator[2] = 2; + + Vector denominator(3); + denominator[0] = 1; + denominator[1] = 2; + denominator[2] = 3; + + Vector quotient(numerator / denominator); + TEST_ASSERT_EQ(quotient[0], 0); + TEST_ASSERT_EQ(quotient[1], 1./2.); + TEST_ASSERT_EQ(quotient[2], 2./3.); +} + + +TEST_CASE(testOperatorTimes) +{ + Vector v1(4); + Vector v2(4); + for (int i = 0; i < 4; i++) + { + v1[i] = i; + v2[i] = i*2.; + } + + Vector v3(v1 * v2); + for (int i = 0; i < 4; i++) + TEST_ASSERT_EQ(v3[i], i * i * 2.); +} + +TEST_CASE(testOperatorDivide) +{ + Vector v1(4); + Vector v2(4); + for (int i = 0; i < 4; i++) + { + v1[i] = i; + v2[i] = i + 2.; + } + + Vector v3(v1 / v2); + for (int i = 0; i < 4; i++) + TEST_ASSERT_EQ(v3[i], i / (i + 2.)); +} + + + + +int main() +{ + TEST_CHECK(testDefaultConstructor); + TEST_CHECK(testScalarConstructor); + TEST_CHECK(testRawConstructor); + TEST_CHECK(testCopyConstructor); + TEST_CHECK(testStdVectorConstructor); + TEST_CHECK(testAssignmentOperator); + TEST_CHECK(testScalarAssignment); + TEST_CHECK(testStdVectorAssignment); + TEST_CHECK(testDotProduct); + TEST_CHECK(testNorm); + TEST_CHECK(testNormalize); + TEST_CHECK(testOperatorPlusEquals); + TEST_CHECK(testOperatorPlus); + TEST_CHECK(testOperatorMinus); + TEST_CHECK(testAdd); + TEST_CHECK(testSubtract); + TEST_CHECK(testOperatorMinus); + TEST_CHECK(testOperatorTimesEquals); + TEST_CHECK(testOperatorTimesEqualsScalar); + TEST_CHECK(testOperatorTimesScalar); + TEST_CHECK(testElementDivision); + TEST_CHECK(testOperatorTimes); + TEST_CHECK(testOperatorDivide); + + // Methods not (yet) tested: + + //TODO: Vector(Matrix2D) constructor. + //TODO: Vector& operator=(const Matrix2D<_T>& mx) + //TODO: Matrix2D<_T>& matrix() + //TODO: const Matrix2D<_T>& matrix() const + //TODO: const std::vector<_T>& vec() const + //TODO: template_T> bool operator==(const Vector_T& v) const + //TODO: template_T> bool operator!=(const Vector_T& v) const + //TODO: template Vector<_T> cross(const Vector<_T>& u, const Vector<_T>& v) + //TODO: template Vector<_T> constantVector(size_t sz, _T cv = 0) + //TODO: template math::linear::Vector<_T> operator*(const math::linear::Matrix2D<_T>& m, const math::linear::Vector<_T>& v) + //TODO: template math::linear::Vector<_T> operator*(_T scalar, const math::linear::Vector<_T>& v) + //TODO: template std::ostream& operator<<(std::ostream& os, const math::linear::Vector<_T>& v) + + return EXIT_SUCCESS; +} diff --git a/modules/c++/math.linear/unittests/test_VectorN.cpp b/modules/c++/math.linear/unittests/test_VectorN.cpp new file mode 100644 index 000000000..514b49c39 --- /dev/null +++ b/modules/c++/math.linear/unittests/test_VectorN.cpp @@ -0,0 +1,463 @@ +/* + * test_VectorN.cpp + * + * Created on: Sep 20, 2012 + * Author: dunstan + * + * Notes: + * + * - Array subscripting is only checked if MATH_LINEAR_BOUNDS is defined + * at compile time. If bounds checking is enabled it is done via an + * assert() call. BUT assert itself is disabled if NDEBUG is defined. + * So you might think you're doing bounds checking when you really + * aren't. + * + * - As of 21 Sept 2012 not all methods are tested. The following are + * not yet tested: + * + * VectorN<,double>(Matrix2D) constructor. + * VectorN<,double>& operator=(const Matrix2D<_T>& mx) + * Matrix2D<_T>& matrix() + * const Matrix2D<_T>& matrix() const + * const std::vector<_T>& vec() const + * template_T> bool operator==(const VectorN<,double>_T& v) const + * template_T> bool operator!=(const VectorN<,double>_T& v) const + * template VectorN<,double><_T> cross(const VectorN<,double><_T>& u, const VectorN<,double><_T>& v) + * template VectorN<,double><_T> constantVectorN<,double>(size_t sz, _T cv = 0) + * template math::linear::VectorN<,double><_T> operator*(const math::linear::Matrix2D<_T>& m, const math::linear::VectorN<,double><_T>& v) + * template math::linear::VectorN<,double><_T> operator*(_T scalar, const math::linear::VectorN<,double><_T>& v) + * template std::ostream& operator<<(std::ostream& os, const math::linear::VectorN<,double><_T>& v) + */ + +#include +#include "TestCase.h" +#include "math/linear/VectorN.h" + +using namespace math::linear; +using namespace std; + + +TEST_CASE(testDefaultConstructor) +{ + // Solaris doesn't like arrays of zero size unless you use -features=zla, + // so I've omitted this test. + //VectorN<0, double> v0; + //TEST_ASSERT_EQ(v0.size(), 0); + + VectorN<1,double> v1; + TEST_ASSERT_EQ(v1.size(), 1); + + VectorN<2,double> v2; + TEST_ASSERT_EQ(v2.size(), 2); +} + + +TEST_CASE(testScalarConstructor) +{ + VectorN<3,double> v(42); + TEST_ASSERT_EQ(v.size(), 3); + TEST_ASSERT_EQ(v[0], 42); + TEST_ASSERT_EQ(v[1], 42); + TEST_ASSERT_EQ(v[2], 42); +} + + +TEST_CASE(testRawConstructor) +{ + double raw[] = {1,2,3}; + VectorN<3,double> v(raw); + TEST_ASSERT_EQ(v.size(), 3); + TEST_ASSERT_EQ(v[0], 1); + TEST_ASSERT_EQ(v[1], 2); + TEST_ASSERT_EQ(v[2], 3); +} + + +TEST_CASE(testCopyConstructor) +{ + VectorN<3,double> vsrc; + vsrc[0] = 1; + vsrc[1] = 2; + vsrc[2] = 3; + VectorN<3,double> v(vsrc); + TEST_ASSERT_EQ(v.size(), 3); + TEST_ASSERT_EQ(v[0], vsrc[0]); + TEST_ASSERT_EQ(v[1], vsrc[1]); + TEST_ASSERT_EQ(v[2], vsrc[2]); + + vsrc[0] = -1; + TEST_ASSERT_EQ(vsrc[0], -1); // should change + TEST_ASSERT_EQ(v[0], 1); // shouldn't change +} + + +TEST_CASE(testStdVectorConstructor) +{ + std::vector stdvec; + stdvec.push_back(10); + stdvec.push_back(11); + stdvec.push_back(12); + + VectorN<3,double> v(stdvec); + TEST_ASSERT_EQ(v.size(), 3); + TEST_ASSERT_EQ(v[0], stdvec[0]); + TEST_ASSERT_EQ(v[1], stdvec[1]); + TEST_ASSERT_EQ(v[2], stdvec[2]); + + stdvec[0] *= -1; + stdvec[1] *= -1; + stdvec[2] *= -1; + + TEST_ASSERT_EQ(v[0], 10); + TEST_ASSERT_EQ(v[1], 11); + TEST_ASSERT_EQ(v[2], 12); +} + + +TEST_CASE(testAssignmentOperator) +{ + VectorN<2,double> vsrc; + vsrc[0] = 42; + vsrc[1] = 99; + VectorN<2,double> v; + v = vsrc; + TEST_ASSERT_EQ(v.size(), 2); + TEST_ASSERT_EQ(v[0], 42); + TEST_ASSERT_EQ(v[1], 99); +} + + +TEST_CASE(testScalarAssignment) +{ + VectorN<5,double> v(123.456); + TEST_ASSERT_EQ(v.size(), 5); + for (int i = 0; i < 5; i++) + TEST_ASSERT_EQ(v[i], 123.456); + + // UNLIKE Vector, scalar assignment doesn't change the size of the + // vector - that's fixed. Instead, it sets every entry in the vector + // to the given value. + v = 99; + TEST_ASSERT_EQ(v.size(), 5); + for (int i = 0; i < 5; i++) + TEST_ASSERT_EQ(v[i], 99); +} + + +TEST_CASE(testStdVectorAssignment) +{ + std::vector stdvec; + stdvec.push_back(10); + stdvec.push_back(11); + stdvec.push_back(12); + + VectorN<3,double> v(-1); + v = stdvec; + TEST_ASSERT_EQ(v.size(), 3); + TEST_ASSERT_EQ(v[0], 10); + TEST_ASSERT_EQ(v[1], 11); + TEST_ASSERT_EQ(v[2], 12); +} + + +TEST_CASE(testDotProduct) +{ + VectorN<5,double> vd1(2); + VectorN<5,double> vd2(3); + const double dotprod(vd1.dot(vd2)); + TEST_ASSERT_EQ(dotprod, 2*3*5); +} + + +TEST_CASE(testNorm) +{ + std::vector stdvec; + stdvec.push_back(10); + stdvec.push_back(11); + stdvec.push_back(12); + VectorN<3,double> vnorm1(stdvec); + const double norm(vnorm1.norm()); + const double arg(10.*10 + 11.*11 + 12.*12); + const double expectedValue(::sqrt(arg)); + TEST_ASSERT_EQ(norm, expectedValue); +} + + +TEST_CASE(testNormalize) +{ + VectorN<4,double> vnorm(4.0); + vnorm.normalize(); + TEST_ASSERT_EQ(vnorm[0], 0.5); + TEST_ASSERT_EQ(vnorm[1], 0.5); + TEST_ASSERT_EQ(vnorm[2], 0.5); + TEST_ASSERT_EQ(vnorm[3], 0.5); +} + + +TEST_CASE(testScale) +{ + VectorN<2,double> vscale(4.0); + vscale.scale(1.0 / 4.0); + TEST_ASSERT_EQ(vscale[0], 1.0); + TEST_ASSERT_EQ(vscale[1], 1.0); +} + + +TEST_CASE(testOperatorPlusEquals) +{ + VectorN<3,double> v1(1); + VectorN<3,double> v2(-1); + + v2 += v1; + + TEST_ASSERT_EQ(v1.size(), 3); + TEST_ASSERT_EQ(v2.size(), 3); + + TEST_ASSERT_EQ(v2[0], 0); + TEST_ASSERT_EQ(v2[1], 0); + TEST_ASSERT_EQ(v2[2], 0); + + TEST_ASSERT_EQ(v1[0], 1); + TEST_ASSERT_EQ(v1[1], 1); + TEST_ASSERT_EQ(v1[2], 1); +} + + +TEST_CASE(testOperatorPlus) +{ + VectorN<3,double> v1(42); + VectorN<3,double> v2(11); + VectorN<3,double> v3; + + v3 = v1 + v2; + + TEST_ASSERT_EQ(v1.size(), 3); + TEST_ASSERT_EQ(v2.size(), 3); + TEST_ASSERT_EQ(v3.size(), 3); + + TEST_ASSERT_EQ(v1[0], 42); + TEST_ASSERT_EQ(v1[1], 42); + TEST_ASSERT_EQ(v1[2], 42); + + TEST_ASSERT_EQ(v2[0], 11); + TEST_ASSERT_EQ(v2[1], 11); + TEST_ASSERT_EQ(v2[2], 11); + + TEST_ASSERT_EQ(v3[0], 53); + TEST_ASSERT_EQ(v3[1], 53); + TEST_ASSERT_EQ(v3[2], 53); +} + + +TEST_CASE(testOperatorMinusEquals) +{ + VectorN<5,double> v1(13); + VectorN<5,double> v2(-5); + + v2 -= v1; + TEST_ASSERT_EQ(v1.size(), 5); + TEST_ASSERT_EQ(v2.size(), 5); + for (int i = 0; i < 5; i++) + TEST_ASSERT_EQ(v2[i], -18); + for (int i = 0; i < 5; i++) + TEST_ASSERT_EQ(v1[i], 13); +} + + +TEST_CASE(testAdd) +{ + VectorN<3,double> v1(2.4); + VectorN<3,double> v2(1.4); + + VectorN<3,double> v3(v2.add(v1)); + + TEST_ASSERT_EQ(v1.size(), 3); + TEST_ASSERT_EQ(v2.size(), 3); + TEST_ASSERT_EQ(v3.size(), 3); + + TEST_ASSERT_EQ(v1[0], 2.4); + TEST_ASSERT_EQ(v1[1], 2.4); + TEST_ASSERT_EQ(v1[2], 2.4); + + TEST_ASSERT_EQ(v2[0], 1.4); + TEST_ASSERT_EQ(v2[1], 1.4); + TEST_ASSERT_EQ(v2[2], 1.4); + + TEST_ASSERT_EQ(v3[0], 3.8); + TEST_ASSERT_EQ(v3[1], 3.8); + TEST_ASSERT_EQ(v3[2], 3.8); +} + + +TEST_CASE(testSubtract) +{ + VectorN<3,double> v1(2.4); + VectorN<3,double> v2(1.4); + + VectorN<3,double> v3(v2.subtract(v1)); + + TEST_ASSERT_EQ(v1.size(), 3); + TEST_ASSERT_EQ(v2.size(), 3); + TEST_ASSERT_EQ(v3.size(), 3); + + TEST_ASSERT_EQ(v1[0], 2.4); + TEST_ASSERT_EQ(v1[1], 2.4); + TEST_ASSERT_EQ(v1[2], 2.4); + + TEST_ASSERT_EQ(v2[0], 1.4); + TEST_ASSERT_EQ(v2[1], 1.4); + TEST_ASSERT_EQ(v2[2], 1.4); + + TEST_ASSERT_EQ(v3[0], -1); + TEST_ASSERT_EQ(v3[1], -1); + TEST_ASSERT_EQ(v3[2], -1); +} + + +TEST_CASE(testOperatorMinus) +{ + VectorN<4,double> v1; + VectorN<4,double> v2; + for (int i = 0; i < 4; i++) + { + v1[i] = i; + v2[i] = -i; + } + VectorN<4,double> v3(v2 - v1); + + TEST_ASSERT_EQ(v1.size(), 4); + TEST_ASSERT_EQ(v2.size(), 4); + TEST_ASSERT_EQ(v3.size(), 4); + + for (int i = 0; i < 4; i++) + { + TEST_ASSERT_EQ(v1[i], i); + TEST_ASSERT_EQ(v2[i], -i); + } + + for (int i = 0; i < 4; i++) + TEST_ASSERT_EQ(v3[i], -2 * i); +} + + +TEST_CASE(testOperatorTimesEquals) +{ + VectorN<4,double> v1; + for (int i = 0; i < 4; i++) + v1[i] = i; + VectorN<4,double> v2; + for (int i = 0; i < 4; i++) + v2[i] = -i; + + v2 *= v1; + + for (int i = 0; i < 4; i++) + TEST_ASSERT_EQ(v1[i], i); + for (int i = 0; i < 4; i++) + TEST_ASSERT_EQ(v2[i], -i * i); +} + + +TEST_CASE(testOperatorTimesEqualsScalar) +{ + VectorN<5,double> v1; + for (int i = 0; i < 5; i++) + v1[i] = i; + + v1 *= 3; + + for (int i = 0; i < 5; i++) + TEST_ASSERT_EQ(v1[i], 3 * i); +} + + +TEST_CASE(testOperatorTimesScalar) +{ + VectorN<5,double> v1; + for (int i = 0; i < 5; i++) + v1[i] = i; + + VectorN<5,double> v2(v1 * 2); + + for (int i = 0; i < 5; i++) + TEST_ASSERT_EQ(v1[i], i); + for (int i = 0; i < 5; i++) + TEST_ASSERT_EQ(v2[i], 2 * i); +} + +TEST_CASE(testElementDivision) +{ + VectorN<3,double> numerator; + numerator[0] = 0; + numerator[1] = 1; + numerator[2] = 2; + + VectorN<3,double> denominator; + denominator[0] = 1; + denominator[1] = 2; + denominator[2] = 3; + + VectorN<3,double> quotient(numerator / denominator); + TEST_ASSERT_EQ(quotient[0], 0); + TEST_ASSERT_EQ(quotient[1], 1./2.); + TEST_ASSERT_EQ(quotient[2], 2./3.); +} + +TEST_CASE(testOperatorTimes) +{ + VectorN<3,double> v1, v2; + for (int i = 0; i < 3; i++) + { + v1[i] = i; + v2[i] = i + 2; + } + + VectorN<3, double> v3(v1 * v2); + for (int i = 0; i < 3; i++) + TEST_ASSERT_EQ(v3[i], i * (i + 2)); +} + + +TEST_CASE(testOperatorDivide) +{ + VectorN<3,double> v1, v2; + for (int i = 0; i < 3; i++) + { + v1[i] = i + 1.; + v2[i] = i + 2.; + } + + VectorN<3, double> v3(v1 / v2); + for (int i = 0; i < 3; i++) + TEST_ASSERT_EQ(v3[i], (i + 1.) / (i + 2.)); +} + + +int main() +{ + TEST_CHECK(testDefaultConstructor); + TEST_CHECK(testScalarConstructor); + TEST_CHECK(testRawConstructor); + TEST_CHECK(testCopyConstructor); + TEST_CHECK(testStdVectorConstructor); + TEST_CHECK(testAssignmentOperator); + TEST_CHECK(testScalarAssignment); + TEST_CHECK(testStdVectorAssignment); + TEST_CHECK(testDotProduct); + TEST_CHECK(testNorm); + TEST_CHECK(testNormalize); + TEST_CHECK(testOperatorPlusEquals); + TEST_CHECK(testOperatorPlus); + TEST_CHECK(testOperatorMinus); + TEST_CHECK(testAdd); + TEST_CHECK(testSubtract); + TEST_CHECK(testOperatorMinus); + TEST_CHECK(testOperatorTimesEquals); + TEST_CHECK(testOperatorTimesEqualsScalar); + TEST_CHECK(testOperatorTimesScalar); + TEST_CHECK(testElementDivision); + TEST_CHECK(testOperatorTimes); + TEST_CHECK(testOperatorDivide); + + return EXIT_SUCCESS; +} diff --git a/modules/c++/math.linear/unittests/test_eigenvalue.cpp b/modules/c++/math.linear/unittests/test_eigenvalue.cpp new file mode 100644 index 000000000..f5c0b4b4c --- /dev/null +++ b/modules/c++/math.linear/unittests/test_eigenvalue.cpp @@ -0,0 +1,98 @@ +/* ========================================================================= + * This file is part of math.linear-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * math.linear-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include "TestCase.h" +#include + +namespace +{ +typedef math::linear::Matrix2D Matrix; +typedef math::linear::Vector Vector; +typedef math::linear::Eigenvalue Eigenvalue; + +TEST_CASE(testNonSymmetric) +{ + Matrix A(4, 4); + A[0][0] = 28; A[0][1] = 69; A[0][2] = 44; A[0][3] = 19; + A[1][0] = 5; A[1][1] = 32; A[1][2] = 38; A[1][3] = 49; + A[2][0] = 10; A[2][1] = 95; A[2][2] = 77; A[2][3] = 45; + A[3][0] = 82; A[3][1] = 3; A[3][2] = 80; A[3][3] = 65; + + Eigenvalue eig(A); + + const Matrix& V(eig.getV()); + Matrix D; + eig.getD(D); + + // It should be the case that A*V == V*D + const Matrix AV = A * V; + const Matrix VD = V * D; + + TEST_ASSERT_EQ(AV.rows(), VD.rows()); + TEST_ASSERT_EQ(AV.cols(), VD.cols()); + + for (size_t row = 0; row < AV.rows(); ++row) + { + for (size_t col = 0; col < VD.cols(); ++col) + { + TEST_ASSERT_ALMOST_EQ(AV[row][col], VD[row][col]); + } + } +} + +TEST_CASE(testSymmetric) +{ + Matrix A(4, 4); + A[0][0] = 28; A[0][1] = 69; A[0][2] = 44; A[0][3] = 82; + A[1][0] = 69; A[1][1] = 32; A[1][2] = 38; A[1][3] = 49; + A[2][0] = 44; A[2][1] = 38; A[2][2] = 77; A[2][3] = 45; + A[3][0] = 82; A[3][1] = 49; A[3][2] = 45; A[3][3] = 65; + + Eigenvalue eig(A); + + const Matrix& V(eig.getV()); + Matrix D; + eig.getD(D); + + // It should be the case that A*V == V*D + const Matrix AV = A * V; + const Matrix VD = V * D; + + TEST_ASSERT_EQ(AV.rows(), VD.rows()); + TEST_ASSERT_EQ(AV.cols(), VD.cols()); + + for (size_t row = 0; row < AV.rows(); ++row) + { + for (size_t col = 0; col < VD.cols(); ++col) + { + TEST_ASSERT_ALMOST_EQ(AV[row][col], VD[row][col]); + } + } +} +} + +int main(int argc, char** argv) +{ + TEST_CHECK(testNonSymmetric); + TEST_CHECK(testSymmetric); + return 0; +} diff --git a/modules/c++/math.linear/unittests/test_lin.cpp b/modules/c++/math.linear/unittests/test_lin.cpp new file mode 100644 index 000000000..34613f4e9 --- /dev/null +++ b/modules/c++/math.linear/unittests/test_lin.cpp @@ -0,0 +1,221 @@ +/* ========================================================================= + * This file is part of math.linear-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * math.linear-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ +#include +#include "TestCase.h" + + +/* + mx::VectorN<3> vec = mx::constantVector<3, double>(1); + vec[0] = fromSample; + vec[1] = fromLine; + // M x P + mx::VectorN<3> result = m3x3 * vec; + sample = result[0]; + line = result[1]; + + */ +using namespace math::linear; + +typedef MatrixMxN<2, 2> Matrix2x2; +typedef MatrixMxN<3, 2> Matrix3x2; +typedef MatrixMxN<3, 3> Matrix3x3; +typedef MatrixMxN<4, 4> Matrix4x4; +typedef VectorN<3> Vector3; +typedef VectorN<2> Vector2; + +TEST_CASE(testEquality) +{ + std::vector v1(3, 3); + Vector<> v2(3, 3); + Vector3 v3(3); + + if (v2 != v1) + TEST_ASSERT(false); + if (v3 != v1) + TEST_ASSERT(false); + + TEST_ASSERT_EQ(v2, v3); + TEST_ASSERT_EQ(v3, v2); +} + +TEST_CASE(testPtrAssign) +{ + std::vector v1(3, 42); + Vector<> v2(v1.size(), &v1[0]); + Vector3 v3(&v1[0]); + + if (v2 != v1) + TEST_ASSERT(false); + TEST_ASSERT_EQ(v2, v3); +} + +TEST_CASE(testSTLVectorAssign) +{ + std::vector v1(3, 42); + Vector<> v2(v1); + Vector3 v3(&v1[0]); + + if (v2 != v1) + TEST_ASSERT(false); + TEST_ASSERT_EQ(v2, v3); +} + +TEST_CASE(testEmptyDim) +{ + Matrix2D AScale(3, 0); +} + +TEST_CASE(testPtrDecorator) +{ + std::vector v1(9, 1); + Matrix2D AScale(3, 3, &v1[0], false); + + AScale.scale(5); + std::vector v5(9, 5); + + // validate that the underlying memory has been mutated + for (size_t i = 0; i < v1.size(); ++i) + TEST_ASSERT_EQ(v1[i], v5[i]); +} + +TEST_CASE(testPtrAdopt) +{ + // valgrind to ensure that we don't have a leak + Matrix2D AScale(3, 3, new double[9], true); +} + +TEST_CASE(testArithmetic) +{ + Matrix2D A = identityMatrix(3); + Matrix3x3 A2( &(A.get())[0] ); + + Vector x = constantVector(3, 1.2); + x[2] = 2; + Vector3 x2(x.matrix().row(0)); + + Vector3 b2 = A2 * x2; + TEST_ASSERT_EQ(b2, x2); + TEST_ASSERT_EQ(x, x2); + TEST_ASSERT_EQ(A2, A); + + Vector b = A * x; + TEST_ASSERT_EQ(b, x); +} + +TEST_CASE(testLinear) +{ + double q[] = + { + 0.681759432346851, -0.469118050335902, -0.561366485689289, + 0.484971425801214, 0.864311190345374, -0.133299971493248, + 0.547728758202852, -0.181368192064663, 0.816761156241381 + }; + + Matrix2D<> mx1(3, 3, q); + Matrix3x3 mx2(q); + + + // This one can do a raw pointer assign + Vector3 u1(mx2.row(0)); + + // This one doesnt know how big it is unless you tell it + Vector<> u2(3, mx1.row(0)); + TEST_ASSERT_EQ(u1, u2); + + // Notice that it doesnt matter which matrix the row came + // from since its a raw pointer + Vector3 u3(mx1.row(0)); + TEST_ASSERT_EQ(u2, u3); + + // Okay, time to get to work + Vector3 v1(mx1.row(1)); + + Vector3 w1 = mx2.row(2); + Vector3 w2 = cross(u1, v1); + TEST_ASSERT_EQ(w2, w1); + + Vector3 w3 = u1.dot(v1); + Vector3 zeros((double)0); + + TEST_ASSERT_EQ(w3, zeros); +} + +TEST_CASE(testNormalize) +{ + double d[] = {0.276922984960890, 0.046171390631154, 0.097131781235848}; + double n[] = {0.932169641471869, 0.155420716185689, 0.326962016904922}; + + Vector3 v1(d); + v1.normalize(); + + Vector<> v2(3, d); + v2.normalize(); + + + TEST_ASSERT_EQ(v1, v2); + TEST_ASSERT_EQ(v2, v1); + + Vector3 truth(n); + + TEST_ASSERT_ALMOST_EQ(v1[0], truth[0]); + TEST_ASSERT_ALMOST_EQ(v1[1], truth[1]); + TEST_ASSERT_ALMOST_EQ(v1[2], truth[2]); +} + +int main() +{ + TEST_CHECK(testEquality); + TEST_CHECK(testNormalize); + TEST_CHECK(testPtrAssign); + TEST_CHECK(testSTLVectorAssign); + TEST_CHECK(testEmptyDim); + TEST_CHECK(testPtrDecorator); + TEST_CHECK(testPtrAdopt); + TEST_CHECK(testArithmetic); + TEST_CHECK(testLinear); + /* + Matrix3x3 A = mx::identityMatrix<3, double>(); + + Vector3 v3 = mx::constantVector<3, double>(1.2); + + v3[2] = 2; + + std::cout << A * v3 << std::endl; + + + std::cout << v3 + v3 << std::endl; + + v3.normalize(); + std::cout << v3 << std::endl; + std::cout << v3.norm() << std::endl; + + std::cout << v3 * 4.0 << std::endl; + + v3 = mx::constantVector<3, double>(0); + v3[0] = 1; + + _V3 y = mx::constantVector<3, double>(0); + y[1] = 1; + + std::cout << cross(v3, y) << std::endl; +*/ +} diff --git a/modules/c++/math.linear/unittests/test_mx.cpp b/modules/c++/math.linear/unittests/test_mx.cpp new file mode 100644 index 000000000..7641c8915 --- /dev/null +++ b/modules/c++/math.linear/unittests/test_mx.cpp @@ -0,0 +1,536 @@ +/* ========================================================================= + * This file is part of math.linear-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * math.linear-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ +#include +#include "TestCase.h" + +using namespace math::linear; + +typedef MatrixMxN<2, 2> Matrix2x2; +typedef MatrixMxN<3, 2> Matrix3x2; +typedef MatrixMxN<3, 3> Matrix3x3; +typedef MatrixMxN<4, 4> Matrix4x4; +typedef MatrixMxN<5, 5> Matrix5x5; + +#define foreach_ij(M, N) \ + for (unsigned int i = 0; i < M; ++i) \ + for (unsigned int j = 0; j < N; ++j) + +TEST_CASE(testIdentityMxN) +{ + Matrix3x3 A = identityMatrix<3, double>(); + foreach_ij(3, 3) + { + if (i == j) + { + TEST_ASSERT_ALMOST_EQ(A(i, j), 1); + } + else + { + TEST_ASSERT_ALMOST_EQ(A(i, j), 0); + } + } + Matrix4x4 B = identityMatrix<4, double>(); + foreach_ij(4, 4) + { + if (i == j) + { + TEST_ASSERT_ALMOST_EQ(B(i, j), 1); + } + else + { + TEST_ASSERT_ALMOST_EQ(B(i, j), 0); + } + } + Matrix2D<> A2 = identityMatrix(3); + TEST_ASSERT_EQ(A, A2); + +} + +TEST_CASE(testScaleMultiplyMxN) +{ + Matrix3x3 A = identityMatrix<3, double>(); + Matrix3x2 B = constantMatrix<3, 2, double>(1); + + B.scale(0.5); + + foreach_ij(3, 2) + { + TEST_ASSERT_ALMOST_EQ(B(i, j), 0.5); + } + + Matrix3x2 C = A * B; + TEST_ASSERT_EQ(B, C); +} + +TEST_CASE(testInvert2x2) +{ + double q[] = + { + -0.326773864841957, 0.945102555946311, + 0.945102555946311, 0.326773864841957 + }; + double correct[] = + { + -0.326773864841957, 0.945102555946311, + 0.945102555946311, 0.326773864841957 + }; + Matrix2x2 Q(q); + + Matrix2x2 Qinv = inverse(Q); + + Matrix2x2 C(correct); + + foreach_ij(2, 2) + { + TEST_ASSERT_ALMOST_EQ_EPS(Qinv(i, j), C(i, j), .0001); + } +} +TEST_CASE(testInvert3x3) +{ + double q[] = + { + -0.8335, -0.3467, 0.4302, + 0.5354, -0.3149, 0.7837, + -0.1362, 0.8835, 0.4481 + }; + + double correct[] = + { + -0.833535710413543, 0.535408997517066, -0.136218298488716, + -0.346676224975467, -0.314923792289617, 0.883537548770105, + 0.430155570116382, 0.783683743883780, 0.448113797009368 + }; + + Matrix3x3 Q(q); + + Matrix3x3 Qinv = inverse(Q); + + Matrix3x3 C(correct); + + foreach_ij(3, 3) + { + TEST_ASSERT_ALMOST_EQ_EPS(Qinv(i, j), C(i, j), .0001); + } + +} + +TEST_CASE(testInvert4x4) +{ + + double q[] = + { + 0.537004, -0.291456, -0.769743, 0.184864, + 0.377207, 0.812143, -0.145395, -0.420713, + 0.678185, 0.025277, 0.573694, 0.458585, + 0.330765, -0.504816, 0.239229, -0.760608 + }; + double qinv[] = + { + 0.537004, 0.377207, 0.678185, 0.330765, + -0.291456, 0.812143, 0.025277, -0.504816, + -0.769743, -0.145395, 0.573694, 0.239229, + 0.184864, -0.420713, 0.458585, -0.760608 + + }; + + + Matrix4x4 Q(q); + Matrix4x4 Qinv = inverse<4, double>(Q); + + Matrix2D<> Q2(4, 4, q); + Matrix2D<> Q2inv = inverse(Q2); + + TEST_ASSERT_EQ(Qinv, Q2inv); + + Matrix4x4 Qtruth(qinv); + + foreach_ij(4, 4) + { + TEST_ASSERT_ALMOST_EQ_EPS(Qinv(i, j), Qtruth(i, j), 0.00001); + } + + double m[] = + { + 9, 7.34847, 7.34847, 6, + 7.34847, 9, 6, 7.34847, + 7.34847, 6, 9, 7.34847, + 6, 7.34847, 7.34847, 9 + }; + double minv[] = + { + 1.0000, -0.8165, -0.8165, 0.6667, + -0.8165, 1.0000, 0.6667, -0.8165, + -0.8165, 0.6667, 1.0000, -0.8165, + 0.6667, -0.8165, -0.8165, 1.0000 + }; + MatrixMxN<4, 4> M(m); + MatrixMxN<4, 4> Mtruth(minv); + MatrixMxN<4, 4> Minv = inverse<4, double>(M); + foreach_ij(4, 4) + { + TEST_ASSERT_ALMOST_EQ_EPS(Minv(i, j), Mtruth(i, j), 0.0001); + } + +} + +TEST_CASE(testOrthoTranspose5x5) +{ + double q[] = + { + 0.206598102328096, -0.258732861775711, -0.366144101439697, 0.808267284061313, 0.320962653355259, + 0.079760655075890, 0.923824193884886, 0.107508570320437, 0.351779072204311, -0.069860492136368, + -0.209804190945734, -0.239598615251375, 0.855978685620244, 0.398355064550789, -0.084784652749218, + -0.755232695854446, -0.020059148734545, -0.347740376127862, 0.229811055794963, -0.505454958536692, + -0.580138982133012, 0.147635697417530, 0.027523169564286, -0.107030850956001, 0.793365826298614 + }; + + Matrix5x5 Q(q); + + Matrix5x5 Qt = Q.transpose(); + + Matrix5x5 I = identityMatrix<5, double>(); + + Matrix5x5 sanitized = tidy(Qt * Q, 0.0001); + TEST_ASSERT_EQ(sanitized, I); + + sanitized = tidy(Q * Qt, 0.0001); + TEST_ASSERT_EQ(sanitized, I); + + // Now do the same for the Matrix2D<> + Matrix2D<> Q2(5, 5, q); + Matrix2D<> Q2t = Q2.transpose(); + + Matrix2D<> sanitized2 = tidy(Q2 * Q2t, 0.0001); + + TEST_ASSERT_EQ(sanitized, sanitized2); + +} + +TEST_CASE(testInvert5x5) +{ + double q[] = + { + -0.1, -0.0, 0.6, -0.3, 0.6, + -0.2, 0.6, -0.1, 0.5, 0.4, + -0.9, 0.0, 0.0, -0.2, -0.3, + 0.3, 0.7, -0.0, -0.5, -0.1, + -0.0, -0.2, -0.7, -0.3, 0.4 + }; + + double correct[] = + { + -0.165907, -0.304698, -0.947308, 0.232976, -0.098678, + -0.115846, 0.667319, 0.131571, 0.800976, -0.194628, + 0.654964, -0.199442, -0.051345, -0.068673, -0.838682, + -0.416854, 0.656088, -0.329889, -0.691226, -0.451030, + 0.775624, 0.476702, -0.271485, -0.238111, 0.596720 + }; + Matrix5x5 Q(q); + + Matrix5x5 C(correct); + Matrix5x5 Qinv = inverse(Q); + foreach_ij(5, 5) + { + TEST_ASSERT_ALMOST_EQ_EPS(Qinv(i, j), C(i, j), .00001); + } + + + Matrix5x5 M = tidy(Q * Qinv, 0.05); + Matrix5x5 I = identityMatrix<5, double>(); + TEST_ASSERT_EQ(M, I); + + Matrix2D<> Q2(5, 5, q); + foreach_ij(5, 5) + { + TEST_ASSERT_ALMOST_EQ(Q2(i, j), Q(i, j)); + } + + Matrix2D<> Q2inv = inverse(Q2); + foreach_ij(5, 5) + { + TEST_ASSERT_ALMOST_EQ(Q2inv(i, j), Qinv(i, j)); + } +} + +TEST_CASE(testSTLVectorAssign) +{ + std::vector v(9); + for (unsigned int i = 0; i < 9; ++i) + v[i] = 2 * (i+1); + + Matrix2x2 A(v); + + TEST_ASSERT_ALMOST_EQ(A(0,0), 2); + TEST_ASSERT_ALMOST_EQ(A(0,1), 4); + TEST_ASSERT_ALMOST_EQ(A(1,0), 6); + TEST_ASSERT_ALMOST_EQ(A(1,1), 8); + + Matrix2D<> A2(2, 2, v); + foreach_ij(2, 2) + { + TEST_ASSERT_ALMOST_EQ(A(i, j), A2(i, j)); + } + + Matrix3x3 B(v); + + TEST_ASSERT_ALMOST_EQ(B(0,0), 2); + TEST_ASSERT_ALMOST_EQ(B(0,1), 4); + TEST_ASSERT_ALMOST_EQ(B(0,2), 6); + TEST_ASSERT_ALMOST_EQ(B(1,0), 8); + TEST_ASSERT_ALMOST_EQ(B(1,1), 10); + TEST_ASSERT_ALMOST_EQ(B(1,2), 12); + TEST_ASSERT_ALMOST_EQ(B(2,0), 14); + TEST_ASSERT_ALMOST_EQ(B(2,1), 16); + TEST_ASSERT_ALMOST_EQ(B(2,2), 18); + + Matrix2D<> B2(3, 3, v); + + foreach_ij(3, 3) + { + TEST_ASSERT_ALMOST_EQ(B(i, j), B2(i, j)); + } +} + +TEST_CASE(testPtrAssign) +{ + double d[] = { 2, 4, 6, 8, 10, 12, 14, 16, 18 }; + + Matrix2x2 A(d); + + TEST_ASSERT_ALMOST_EQ(A(0,0), 2); + TEST_ASSERT_ALMOST_EQ(A(0,1), 4); + TEST_ASSERT_ALMOST_EQ(A(1,0), 6); + TEST_ASSERT_ALMOST_EQ(A(1,1), 8); + + Matrix2D<> A2(2, 2, d); + foreach_ij(2, 2) + { + TEST_ASSERT_ALMOST_EQ(A(i, j), A2(i, j)); + } + Matrix3x3 B(d); + + TEST_ASSERT_ALMOST_EQ(B(0,0), 2); + TEST_ASSERT_ALMOST_EQ(B(0,1), 4); + TEST_ASSERT_ALMOST_EQ(B(0,2), 6); + TEST_ASSERT_ALMOST_EQ(B(1,0), 8); + TEST_ASSERT_ALMOST_EQ(B(1,1), 10); + TEST_ASSERT_ALMOST_EQ(B(1,2), 12); + TEST_ASSERT_ALMOST_EQ(B(2,0), 14); + TEST_ASSERT_ALMOST_EQ(B(2,1), 16); + TEST_ASSERT_ALMOST_EQ(B(2,2), 18); + Matrix2D<> B2(3, 3, d); + + foreach_ij(3, 3) + { + TEST_ASSERT_ALMOST_EQ(B(i, j), B2(i, j)); + } + +} + +TEST_CASE(testPermuteInvert2x2) +{ + std::vector p(2); + p[0] = 1; + p[1] = 0; + + Matrix2x2 I = identityMatrix<2, double>(); + Matrix2x2 G = I.permute(p); + TEST_ASSERT_ALMOST_EQ(G(0,0), 0); + TEST_ASSERT_ALMOST_EQ(G(0,1), 1); + TEST_ASSERT_ALMOST_EQ(G(1,1), 0); + TEST_ASSERT_ALMOST_EQ(G(1,0), 1); + Matrix2x2 H = inverse<2, double>(G); + + Matrix2x2 F = H.permute(p); + TEST_ASSERT_EQ(I, F); + + Matrix2D<> I2 = identityMatrix(2); + TEST_ASSERT_EQ(I, I2); + + std::vector p2(2, 0); + p2[0] = 1; + Matrix2D<> G2 = I2.permute(p2); + TEST_ASSERT_EQ(G2, G); + + Matrix2D<> H2 = inverse(G2); + + TEST_ASSERT_EQ(H, H2); + +} + +TEST_CASE(testSetCols) +{ + MatrixMxN<3, 2> A(0.0); + Matrix2D<> A2(3, 2); + // Make it so each column vector has the same values + std::vector v(3); + v[0] = 1; + v[1] = 2; + v[2] = 3; + A.col(0, v); + A.col(1, &v[0]); + + A2.col(0, v); + A2.col(1, &v[0]); + foreach_ij(3, 2) + { + TEST_ASSERT_ALMOST_EQ(A(i, j), i + 1); + TEST_ASSERT_ALMOST_EQ(A2(i, j), i + 1); + } +} + +TEST_CASE(testSetRows) +{ + MatrixMxN<3, 2> A; + Matrix2D<> A2(3, 2); + std::vector v(3, 0); + v[0] = 1; + v[1] = 2; + + A.row(0, v); + A.row(1, &v[0]); + A(2, 0) = v[0]; + A(2, 1) = v[1]; + + A2.row(0, v); + A2.row(1, &v[0]); + A2(2, 0) = v[0]; + A2(2, 1) = v[1]; + + foreach_ij(3, 2) + { + TEST_ASSERT_ALMOST_EQ(A(i, j), j + 1); + TEST_ASSERT_ALMOST_EQ(A2(i, j), j + 1); + } + //std::cout << A << std::endl; +} +TEST_CASE(testGrabCols) +{ + MatrixMxN<3, 2> A; + Matrix2D<> A2(3, 2); + foreach_ij(3, 2) + { + A(i, j) = (i+1)*(j+1); + A2(i, j) = A(i, j); + } + + for (size_t j = 0; j < A.cols(); ++j) + { + std::vector cols = A.col(j); + std::vector cols2 = A2.col(j); + + for (unsigned int i = 0; i < A2.rows(); ++i) + { + TEST_ASSERT_ALMOST_EQ(cols[i], cols2[i]); + } + } +} + +TEST_CASE(testGrabRows) +{ + MatrixMxN<3, 2> A; + Matrix2D<> A2(3, 2); + foreach_ij(3, 2) + { + A(i, j) = (i+1)*(j+1); + A2(i, j) = A(i, j); + } + for (size_t i = 0; i < A.rows(); ++i) + { + double* rows = A.row(i); + double* rows2 = A2.row(i); + TEST_ASSERT_EQ(A[i], rows); + TEST_ASSERT_EQ(A2[i], rows2); + + for (unsigned int j = 0; j < A2.cols(); ++j) + { + TEST_ASSERT_ALMOST_EQ(rows[j], rows2[j]); + } + } +} + + + +TEST_CASE(testArithmeticMxN) +{ + // 2 1 + // 1 3 + Matrix2x2 D(1); + D(0, 0) = 2; + D(1, 1) = 3; + + // 3 2 + // 2 2 + Matrix2x2 E(2); + E(0, 0) = 3; + + Matrix2x2 F = identityMatrix<2, double>(); + + + Matrix2x2 G = (D * E) - F; + + TEST_ASSERT_ALMOST_EQ(G(0,0), 7); + TEST_ASSERT_ALMOST_EQ(G(0,1), 6); + TEST_ASSERT_ALMOST_EQ(G(1,1), 7); + TEST_ASSERT_ALMOST_EQ(G(1,0), 9); + + Matrix2D<> D2(2, 2, 1); + D2(0, 0) = 2; + D2(1, 1) = 3; + TEST_ASSERT_EQ(D, D2); + // 3 2 + // 2 2 + Matrix2D<> E2(2, 2, 2); + E2(0, 0) = 3; + TEST_ASSERT_EQ(E, E2); + + Matrix2D<> F2 = identityMatrix(2); + TEST_ASSERT_EQ(F, F2); + + Matrix2D<> G2 = (D2 * E2) - F2; + TEST_ASSERT_EQ(G2, G); + + +} + +int main() +{ + + + TEST_CHECK(testIdentityMxN); + TEST_CHECK(testScaleMultiplyMxN); + TEST_CHECK(testSetRows); + TEST_CHECK(testGrabRows); + TEST_CHECK(testSetCols); + TEST_CHECK(testGrabCols); + TEST_CHECK(testArithmeticMxN); + TEST_CHECK(testPermuteInvert2x2); + TEST_CHECK(testInvert2x2); + TEST_CHECK(testInvert3x3); + TEST_CHECK(testInvert4x4); + TEST_CHECK(testInvert5x5); + TEST_CHECK(testPtrAssign); + TEST_CHECK(testSTLVectorAssign); + TEST_CHECK(testOrthoTranspose5x5); + + +} diff --git a/modules/c++/math.linear/wscript b/modules/c++/math.linear/wscript new file mode 100644 index 000000000..7465af5e0 --- /dev/null +++ b/modules/c++/math.linear/wscript @@ -0,0 +1,9 @@ +NAME = 'math.linear' +MAINTAINER = 'jmrandol@users.sourceforge.net' +VERSION = '0.2' +MODULE_DEPS = 'sys mem' + +options = configure = distclean = lambda p: None + +def build(bld): + bld.module(**globals()) diff --git a/modules/c++/math.poly/include/import/math/poly.h b/modules/c++/math.poly/include/import/math/poly.h new file mode 100644 index 000000000..86539a175 --- /dev/null +++ b/modules/c++/math.poly/include/import/math/poly.h @@ -0,0 +1,32 @@ +/* ========================================================================= + * This file is part of math.poly-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * math.poly-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __MATH_POLY_H__ +#define __MATH_POLY_H__ + +#include "math/poly/OneD.h" +#include "math/poly/TwoD.h" +#include "math/poly/Fixed1D.h" +#include "math/poly/Fixed2D.h" +#include "math/poly/Fit.h" + +#endif // __MATH_POLY_H__ diff --git a/modules/c++/math.poly/include/math/poly/Fit.h b/modules/c++/math.poly/include/math/poly/Fit.h new file mode 100644 index 000000000..15c8dd0f7 --- /dev/null +++ b/modules/c++/math.poly/include/math/poly/Fit.h @@ -0,0 +1,255 @@ +#ifndef __MATH_POLY_FIT_H__ +#define __MATH_POLY_FIT_H__ + +namespace math +{ +namespace poly +{ + +/*! + * Templated function to perform a linear least squares fit for the data. + * This algorithm is fairly straightforward. + * + * To fit an order N polynomial, we need to solve + * Ax=b, for x. + * + * A is a system of polynomials, e.g. + * + * f(x) = c0 + c1*x + c2*x^2 + c3*x^3 = y + * + * Each observed point in the data sets is computed + * for our A matrix. + * + * e.g.: f(1) = 3, f(-1) = 13, f(2) 1, f(-2) = 33 + * + * | 1 1 1 1 || c0 | | 3 | + * | 1 -1 1 -1 || c1 | = | 13 | + * | 1 2 4 8 || c2 | | 1 | + * | 1 -2 4 -8 || c3 | | 33 | + * + * + * Linear least squares solution for system where + * ker(A) = {0} (IOW, there are free variables) + * + * x = inv(A' * A) * A' * b + * + * \param x The observable x points + * \param y The observable y solutions + * \return A one dimensional polynomial that fits the curve + */ + +template OneD fit(const Vector_T& x, + const Vector_T& y, + size_t numCoeffs) +{ + + math::linear::Vector vy(y); + // n is polynomial order + size_t sizeX = x.size(); + + math::linear::Matrix2D A(x.size(), numCoeffs + 1); + + for (size_t i = 0; i < sizeX; i++) + { + // The c0 coefficient is a freebie + A(i, 0) = 1; + double v = x[i]; + A(i, 1) = v; + for (size_t j = 2; j <= numCoeffs; j++) + { + A(i, j) = std::pow(v, (double)j); + } + } + + math::linear::Matrix2D At = A.transpose(); + math::linear::Matrix2D inv = inverse(At * A); + math::linear::Matrix2D B = inv * At; + math::linear::Vector c(B * vy.matrix()); + // use the vector constructor + std::vector cv(c.size()); + std::copy(c.get(), c.get()+c.size(), cv.begin()); + return math::poly::OneD(cv); +} + + +/*! + * This method allows us to fit a set of observations using raw + * pointers + */ +inline OneD fit(size_t numObs, const double* x, const double* y, + size_t numCoeffs) +{ + math::linear::Vector xv(numObs, x); + math::linear::Vector yv(numObs, y); + return math::poly::fit >(xv, yv, numCoeffs); +} + + +/*! + * Two-dimensional linear least squares fit + * To make sure that one dimension does not dominate the other, + * we normalize the x and y matrices. + * + * The x, y and z matrices must all be the same size, and the + * x(i, j) point in X must correspond to y(i, j) in Y + * + * \param x Input x coordinate + * \param y Input y coordinates + * \param z Observed outputs + * \param nx The requested order X of the output poly + * \param ny The requested order Y of the output poly + * \throw Exception if matrices are not equally sized + * \return A polynomial, f(x, y) = z + */ + +inline math::poly::TwoD fit(const math::linear::Matrix2D& x, + const math::linear::Matrix2D& y, + const math::linear::Matrix2D& z, + size_t nx, + size_t ny) +{ + // Normalize the values in the matrix + size_t m = x.rows(); + size_t n = x.cols(); + + if (m != y.rows()) + throw except::Exception(Ctxt("Matrices must be equally sized")); + + if (n != y.cols()) + throw except::Exception(Ctxt("Matrices must be equally sized")); + + double xacc = 0.0; + double yacc = 0.0; + for (size_t i = 0; i < m; i++) + { + for (size_t j = 0; j < n; j++) + { + xacc += x(i, j) * x(i, j); + yacc += y(i, j) * y(i, j); + } + } + + // by num elements + size_t mxn = m*n; + + xacc /= (double)mxn; + yacc /= (double)mxn; + + double rxrms = 1/std::sqrt(xacc); + double ryrms = 1/std::sqrt(yacc); + + // Scalar division + + math::linear::Matrix2D xp = x * rxrms; + math::linear::Matrix2D yp = y * ryrms; + + size_t acols = (nx+1) * (ny+1); + + // R = M x N + // C = NX+1 x NY+1 + + // size(A) = R x P + math::linear::Matrix2D A(mxn, acols); + + for (size_t i = 0; i < m; i++) + { + size_t xidx = i*n; + for (size_t j = 0; j < n; j++) + { + + // We are doing an accumulation of pow()s to get this + + // Pre-calculate these + double xij = xp(i, j); + double yij = yp(i, j); + + xacc = 1; + + for (size_t k = 0; k <= nx; k++) + { + size_t yidx = k * (ny + 1); + yacc = 1; + + for (size_t l = 0; l <= ny; l++) + { + + A(xidx, yidx) = xacc * yacc; + yacc *= yij; + ++yidx; + + } + xacc *= xij; + } + // xidx: i*n + j; + xidx++; + } + } + + // size(tmp) = R x 1 + math::linear::Matrix2D tmp(mxn, 1); + + for (size_t i = 0; i < m; i++) + { + for (size_t j = 0; j < n; j++) + { + tmp(i*n + j, 0) = z(i, j); + } + } + + math::linear::Matrix2D At = A.transpose(); + + // T + // size(A A) = (P x R) (R x P) = (P x P) + // size(inv) = (P x P) + math::linear::Matrix2D inv = math::linear::inverse(At * A); + + // size(C) = ((P x P) (P x R))(R x 1) + // = (P x R)(R x 1) + // = (P x 1) + // = (NX+1xNY+1 x 1) + + math::linear::Matrix2D C = inv * At * tmp; + + // Now we need the NX+1 components out for our x coeffs + // and NY+1 components out for our y coeffs + math::poly::TwoD coeffs(nx, ny); + + xacc = 1; + size_t p = 0; + for (size_t i = 0; i <= nx; i++) + { + yacc = 1; + for (size_t j = 0; j <= ny; j++) + { + coeffs[i][j] = C(p, 0)*(xacc * yacc); + ++p; + yacc *= ryrms; + } + xacc *= rxrms; + } + return coeffs; + + +} + +inline math::poly::TwoD fit(size_t numRows, + size_t numCols, + const double* x, + const double* y, + const double* z, + size_t nx, + size_t ny) +{ + math::linear::Matrix2D xm(numRows, numCols, x); + math::linear::Matrix2D ym(numRows, numCols, y); + math::linear::Matrix2D zm(numRows, numCols, z); + + return fit(xm, ym, zm, nx, ny); +} + + +} + +} + +#endif diff --git a/modules/c++/math.poly/include/math/poly/Fixed1D.h b/modules/c++/math.poly/include/math/poly/Fixed1D.h new file mode 100644 index 000000000..86509e4d7 --- /dev/null +++ b/modules/c++/math.poly/include/math/poly/Fixed1D.h @@ -0,0 +1,386 @@ +/* ========================================================================= + * This file is part of math.poly-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * math.poly-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __MATH_POLY_FIXED_1D_H__ +#define __MATH_POLY_FIXED_1D_H__ + +#include +#include +#include "math/poly/OneD.h" + +namespace math +{ +namespace poly +{ + +/*! + * One dimensional fixed size polynomial. This is similar to the + * math::poly::OneD<_T> type except the user must know the size. + * + * When a mutating method is used, such as *=, the order is fixed and + * therefore any higher information is lost, therefore, if higher-order + * precision is required, the dev. should use the non-mutating methods, + * such as * + * + * We talk about polynomials in terms of orders, but orders are one less + * than the total number of terms, since there is a constant term as well. + * Its easier to think of polynomials this way, so we leave the standard + * notation, and compensate by iterating one extra in all of our loops + * + */ +template class Fixed1D +{ +protected: + _T mCoef[_Order+1]; +public: + + /*! + * Default constructor clears memory + * + */ + Fixed1D() + { + // Initialize coefficents; + for (size_t i = 0; i < _Order+1; i++) + { + mCoef[i] = 0; + } + } + + /*! + * Unlike the non-fixed size poly, this constructor + * will truncate higher orders. This is what we want. + */ + Fixed1D(const OneD<_T>& coeff) + { + size_t sizeC = coeff.order(); + sizeC = std::min(sizeC, _Order); + for (size_t i = 0; i <= sizeC; i++) + { + mCoef[i] = coeff[i]; + } + } + + /*! + * Unlike the non-fixed size poly, this constructor + * will truncate higher orders. This allows us to do something like + * \code + * Fixed1D<2> quadratic; + * Fixed1D<3> cubicCopy(quadratic); + * \code + * + */ + template Fixed1D(const Fixed1D<_OtherOrder, _T>& coeff) + { + + size_t sizeC = std::min(_OtherOrder, _Order); + for (size_t i = 0; i <= sizeC; i++) + { + mCoef[i] = coeff[i]; + } + } + + inline size_t order() const { return _Order; } + inline size_t size() const { return _Order + 1; } + + /*! + * + * Get a fixed polynomial from a non-fixed one + * + */ + Fixed1D<_Order, _T>& operator=(const OneD<_T>& coeff) + { + size_t sizeC = coeff.order(); + sizeC = std::min(sizeC, _Order); + for (size_t i = 0; i <= sizeC; i++) + { + mCoef[i] = coeff[i]; + } + return *this; + } + + template Fixed1D<_Order, _T>& operator=(const Fixed1D<_OtherOrder, _T>& coeff) + { + + unsigned int sizeC = std::min(_OtherOrder, _Order); + for (size_t i = 0; i <= sizeC; i++) + { + mCoef[i] = coeff[i]; + } + return *this; + } + + + + /*! + * Evaluate our polynomial at 'at' + * + */ + _T operator() (double at) const + { + double rv(0); + double atPower = 1; + + for (size_t i = 0; i <= _Order; i++) + { + rv += mCoef[i]*atPower; + atPower *= at; + } + return rv; + } + + /*! + * Integrate between start and end + * + */ + _T integrate(double start, double end) const + { + _T rv(0); + double div; + double newCoef; + double endAtPower = end; + double startAtPower = start; + + for (size_t i = 0; i <= _Order; i++) + { + div = 1.0/(i + 1); + newCoef = mCoef[i] * div; + rv += newCoef * endAtPower; + rv -= newCoef * startAtPower; + endAtPower *= end; + startAtPower *= start; + + } + return rv; + } + + /*! + * Take the derivative of the polynomial. This produces an order- + * lower polynomial as output. + */ + Fixed1D<_Order-1, _T> derivative() const + { + Fixed1D<_Order-1, _T> dv; + if (_Order) + { + for (size_t i = 0; i <= _Order-1; i++) + { + dv[i] = mCoef[i+1] * (i+1); + } + } + return dv; + } + /*! + * + * + */ + _T& operator [] (size_t i) + { + if (i > _Order) + throw except::IndexOutOfRangeException(Ctxt(FmtX("index [%d] is not in range [0..%d]", i, _Order))); + return mCoef[i]; + + } + _T operator [] (size_t i) const + { + if (i > _Order) + throw except::IndexOutOfRangeException(Ctxt(FmtX("index [%d] is not in range [0..%d]", i, _Order))); + + return mCoef[i]; + + } + + + /*! + * Mult-assign (mutating method) + * + */ + + Fixed1D<_Order, _T>& operator*=(double cv) + { + for (size_t i = 0; i <= _Order; i++) + { + mCoef[i] *= cv; + } + return *this; + } + /*! + * Multiply (non mutating) + * + */ + Fixed1D<_Order, _T> operator*(double cv) const + { + + Fixed1D<_Order, _T> m(*this); + m *= cv; + + return m; + } + + /*! + * Important note. We do not increase the order here, so be careful. + * If you need to increase the order, you should use the other + * method below (non-mutating) + */ + template + Fixed1D<_Order>& operator *= (const Fixed1D<_OtherOrder>& p) + { + // Multiply another into this and do not increase the order + Fixed1D<_Order+_OtherOrder> newPoly = *this * p; + + // We need to be careful to overload this properly + *this = newPoly; + return *this; + } + + template + Fixed1D<_Order+_OtherOrder, _T> + operator * (const Fixed1D<_OtherOrder, _T>& p) const + { + // Multiply this one by another, and increase the order + //Fixed1D<_Order+_OtherOrder, _T> copy(*this); + Fixed1D<_Order+_OtherOrder, _T> newPoly; + + for (size_t i = 0; i <= _Order; i++) + { + for (size_t j = 0; j <= _OtherOrder; j++) + { + newPoly[i+j] += mCoef[i] * p[j]; + } + } + return newPoly; + + } + + /* These are the trickiest, since we cant know anything at compile time */ + template + Fixed1D<_Order+_OtherOrder, _T> + operator+(const Fixed1D<_OtherOrder, _T>& p) const + { + Fixed1D<_Order+_OtherOrder, _T> newPoly; + if (_Order > _OtherOrder) + { + newPoly = *this; + for (size_t i = 0; i <= _OtherOrder; i++) + { + newPoly[i] += p[i]; + } + } + else + { + newPoly = p; + for (size_t i = 0; i <= _Order; i++) + { + newPoly[i] += mCoef[i]; + } + } + return newPoly; + + } + template + Fixed1D<_Order+_OtherOrder, _T> + operator-(const Fixed1D<_OtherOrder, _T>& p) const + { + + return *this + (p * -1.0); + + } + // In this one, if you try and mutate, we will not change the order + template + Fixed1D<_Order, _T>& operator += (const Fixed1D<_OtherOrder, _T>& p) + { + *this = *this + p; + return *this; + + } + /*! + * + * + */ + template + Fixed1D<_Order, _T>& operator -= (const Fixed1D<_OtherOrder, _T>& p) + { + *this = *this - p; + return *this; + } + + + /*! + * Mult-assign by the reciprocal + * + */ + + template + Fixed1D<_Order, _T>& operator /= (double cv) + { + double recip = 1.0/cv; + for (size_t i = 0; i <= _Order; i++) + { + mCoef[i] *= recip; + } + return *this; + } + + /*! + * Make a copy of this, and mult-assign it + * + */ + Fixed1D<_Order, _T> operator / (double cv) const + { + Fixed1D<_Order, _T> copy(*this); + copy *= (1.0/cv); + return copy; + } + +}; + +/*! + * Actually, this is the same as p * cv, so we just reverse it + * + */ +template + Fixed1D<_Order, _T> operator*(double cv, + const Fixed1D<_Order, _T>& p) +{ + return p*cv; +} + + + +} +} + +/*! + * Print our poly (y first, so the 2D version looks right) + */ +template + std::ostream& operator << (std::ostream& out, + const math::poly::Fixed1D<_Order, _T>& p) +{ + for (size_t i = 0 ; i <= _Order; i++) + { + out << p[i] << "*y^" << i << " "; + } + return out; +} + +#endif diff --git a/modules/c++/math.poly/include/math/poly/Fixed2D.h b/modules/c++/math.poly/include/math/poly/Fixed2D.h new file mode 100644 index 000000000..4f92710a0 --- /dev/null +++ b/modules/c++/math.poly/include/math/poly/Fixed2D.h @@ -0,0 +1,368 @@ +/* ========================================================================= + * This file is part of math.poly-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * math.poly-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __MATH_POLY_FIXED_2D_H__ +#define __MATH_POLY_FIXED_2D_H__ + +#include "math/poly/Fixed1D.h" + +namespace math +{ +namespace poly +{ + +/*! + * This class is similar to the TwoD<_T> except that it uses a fixed + * size for order. As in the Fixed1D case, the order in each dim is one + * less than the size of the coefficients. + */ +template class Fixed2D +{ +protected: + Fixed1D<_OrderY, _T> mCoef[_OrderX+1]; +public: + Fixed2D() {} + + template + Fixed2D(const Fixed2D<_OtherOrderX, _OtherOrderY, _T>& coeff) + { + + size_t sizeC = std::min(_OtherOrderX, _OrderX); + for (size_t i = 0; i <= sizeC; i++) + { + mCoef[i] = coeff[i]; + } + } + + + + Fixed2D(const TwoD<_T>& coeff) + { + + size_t sizeC = std::min(coeff.orderX(), _OrderX); + for (size_t i = 0; i <= sizeC; i++) + { + mCoef[i] = coeff[i]; + } + } + + Fixed2D<_OrderX, _OrderY, _T>& operator=(const TwoD<_T>& coeff) + { + + size_t sizeC = std::min(coeff.orderX(), _OrderX); + for (size_t i = 0; i <= sizeC; i++) + { + mCoef[i] = coeff[i]; + } + return *this; + } + + template + Fixed2D<_OrderX, _OrderY, _T>& + operator=(const Fixed2D<_OtherOrderX, _OtherOrderY, _T>& coeff) + { + + size_t sizeC = std::min(_OtherOrderX, _OrderX); + for (size_t i = 0; i <= sizeC; i++) + { + mCoef[i] = coeff[i]; + } + return *this; + } + + size_t orderX() const { return _OrderX; } + size_t orderY() const { return _OrderY; } + + inline _T operator()(double atX, double atY) const + { + _T rv(0); + double atXPower(1); + + for (size_t i = 0; i <= _OrderX; i++) + { + rv += mCoef[i](atY)*atXPower; + atXPower *= atX; + + } + return rv; + } + _T integrate(double startX, double endX, double startY, double endY) const + { + _T rv(0); + double div(0); + double endAtPower = endX; + double startAtPower = startX; + double newCoef; + for (size_t i = 0; i <= _OrderX; i++) + { + div = 1.0/(i+1); + newCoef = mCoef[i].integrate(startY, endY) * div; + rv += newCoef * endAtPower; + rv -= newCoef * startAtPower; + endAtPower *= endX; + startAtPower *= startX; + + } + return rv; + } + + Fixed2D<_OrderX, _OrderY, _T> flipXY() const + { + Fixed2D<_OrderX, _OrderY, _T> prime; + for (size_t ii = 0; ii <= _OrderX; ++ii) + { + for (size_t jj = 0; jj <= _OrderY; ++jj) + { + prime[ii][jj] = mCoef[jj][ii]; + } + } + + return prime; + } + + // Will not work with order 0! + Fixed2D<_OrderX, _OrderY-1, _T> derivativeY() const + { + if (!_OrderY) + throw except::Exception(Ctxt("Must have order 1 in Y")); + Fixed2D<_OrderX, _OrderY-1, _T> dy; + + for (size_t i = 0; i <= _OrderX; i++) + { + dy[i] = mCoef[i].derivative(); + } + return dy; + } + Fixed2D<_OrderX-1, _OrderY, _T> derivativeX() const + { + if (!_OrderX) + throw except::Exception(Ctxt("Must have order 1 in Y")); + Fixed2D<_OrderX-1, _OrderY, _T> dx; + for (size_t i = 0; i <= _OrderX-1; i++) + { + dx[i] = mCoef[i+1] * (_T)(i+1); + } + return dx; + + } + + Fixed2D<_OrderX-1, _OrderY-1, _T> derivativeXY() const + { + Fixed2D<_OrderX-1, _OrderY-1> rv = derivativeY().derivativeX(); + return rv; + } + Fixed1D<_OrderX, _T> atY(double y) const + { + if (!_OrderX) + throw except::Exception(Ctxt("Must have order 1 in Y")); + + // We will have a 1D poly of order X + Fixed1D<_OrderX, _T> polyY; + + for (size_t i = 0; i <= _OrderX; i++) + { + polyY[i] = mCoef[i](y); + } + return polyY; + + } + inline Fixed1D<_OrderY, _T> operator[](size_t i) const + { + return mCoef[i]; + } + + inline Fixed1D<_OrderY, _T>& operator[](size_t i) + { + return mCoef[i]; + } + + Fixed2D<_OrderX, _OrderY, _T> operator * (double cv) const + { + Fixed2D<_OrderX, _OrderY> copy(*this); + + for (size_t i = 0; i <= _OrderX; i++) + { + copy[i] *= cv; + } + return copy; + + } + /*! + * As in the one D case, we make sure that only the multiply does + * the real work. Here we just cut down the order (truncate) to + * whatever order we already have + */ + template + Fixed2D<_OrderX, _OrderY, _T>& operator *= (const Fixed2D<_OtherOrderX, _OtherOrderY, _T>& p) + { + Fixed2D<_OrderX+_OtherOrderX, _OrderY+_OtherOrderY> newPoly + = *this * p; + *this = newPoly; + } + + /*! + * We need to be careful with this operation. Our new polynomial + * will have order X1 + X2, Y1 + Y2, and since we may want to truncate + * we can use either self-assignment or the overloaded copy operator. + * + */ + template + Fixed2D<_OrderX+_OtherOrderX, _OrderY+_OtherOrderY, _T> + operator * (const Fixed2D<_OtherOrderX, _OtherOrderY, _T>& p) const + { + Fixed2D<_OrderX+_OtherOrderX, _OrderY+_OtherOrderY, _T> copy(*this); + Fixed2D<_OrderX+_OtherOrderX, _OrderY+_OtherOrderY, _T> newPoly; + + for (size_t i = 0; i <= _OrderX; i++) + { + for (size_t j = 0; j <= _OtherOrderX; j++) + { + // This produces a new polynomial which uses the + // copy constructor + newPoly[i+j] += copy[i] * p[j]; + } + + } + return newPoly; + + } + template + Fixed2D<_OrderX, _OrderY, _T>& operator += (const Fixed2D<_OtherOrderX, _OtherOrderY, _T>& p) + { + *this = *this + p; + } + + template + Fixed2D<_OrderX+_OtherOrderX, _OrderY+_OtherOrderY, _T> + operator+(const Fixed2D<_OtherOrderX, _OtherOrderY, _T>& p) const + + { + Fixed2D<_OrderX+_OtherOrderX, _OrderY+_OtherOrderY, _T> copy(*this); + + for (size_t i = 0; i <= _OtherOrderX; i++) + { + copy[i] += p[i]; + } + return copy; + + } + + template + Fixed2D<_OrderX, _OrderY, _T>& operator-=(const Fixed2D<_OtherOrderX, _OtherOrderY, _T>& p) + { + + *this = *this + (p * -1); + return *this; + + } + template + Fixed2D<_OrderX+_OtherOrderX, _OrderY+_OtherOrderY, _T> + operator - (const Fixed2D<_OtherOrderX, _OtherOrderY, _T>& p) const + { + return *this + (p * -1); + + + } + Fixed2D<_OrderX, _OrderY, _T>& operator /= (double cv) + { + for (size_t i = 0; i <= _OrderX; i++) + { + mCoef[i] /= cv; + } + return *this; + } + + Fixed2D<_OrderX, _OrderY, _T> operator / (double cv) const + { + Fixed2D<_OrderX, _OrderY> copy(*this); + + for (size_t i = 0; i <= _OrderX; i++) + { + copy[i] /= cv; + } + return copy; + + + } +/* + // Be careful that output order is high enough + template + Fixed2D<_OrderX, _OrderY, _T> power(int toThe) const + { + // If its 0, we have to give back a 1*x^0*y^0 poly, since + // we want a 2D poly out + Fixed2D<_OrderX*toThe, _OrderY*toThe> rv; + + if (toThe == 0) + { + rv[0][0] = 1; + return rv; + } + rv = *this; + + if (toThe == 1) + { + return rv; + } + + for (int i = 2; i <= toThe; i++) + { + rv *= *this; + } + return rv; + } + + +*/ + + + +}; + + +} +} + +template +math::poly::Fixed2D<_OrderX, _OrderY, _T> + operator * (double cv, const math::poly::Fixed2D<_OrderX, _OrderY, _T>& p) +{ + math::poly::Fixed2D<_OrderX, _OrderY> copy(p); + + for (size_t i = 0; i <= _OrderX; i++) + { + copy[i] *= cv; + } + return copy; +} + +template +std::ostream& +operator << (std::ostream& out, const math::poly::Fixed2D<_OtherOrderX, _OtherOrderY, _T>& p) +{ + for (size_t i = 0 ; i <= _OtherOrderX ; i++) + { + out << "x^" << i << "*(" << p[i] << ")" << std::endl; + } + return out; +} +#endif diff --git a/modules/c++/math.poly/include/math/poly/OneD.h b/modules/c++/math.poly/include/math/poly/OneD.h new file mode 100644 index 000000000..196cebaf6 --- /dev/null +++ b/modules/c++/math.poly/include/math/poly/OneD.h @@ -0,0 +1,199 @@ +/* ========================================================================= + * This file is part of math.poly-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * math.poly-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __MATH_POLY_ONED_H__ +#define __MATH_POLY_ONED_H__ + +#include +#include +#include +#include +#include + +namespace math +{ +namespace poly +{ +/*! + * \class OneD + * \brief 1-D polynomial evaluation + * + * This class defines an implementation for a 1-D polynomial. It should + * support datatypes that allow the following operators: + * _T(0), _T*_T, _T*=_T, _T+_T, _T+=_T, _T-_T, _T-=_T, -T* + * + * It supports polynomials of the form: + * a0 + a1*x + a2*x^2 + ... (in ascending powers) + * + * It supports evaluating the integral over a specified interval (a...b) + * + * It supports computing the derivative and + * the multiplication/addition/subtraction of 1-D polynomials. + */ +template +class OneD +{ +protected: + std::vector<_T> mCoef; + +public: + /*! + * The polynomial is invalid (i.e. size() will return 0 and order() will + * throw) + */ + OneD() + { + } + + /*! + * A vector of ascending power coefficients (note that + * this is the reverse of Matlab) + */ + OneD(const std::vector<_T>& coef) : + mCoef(coef) + { + if (mCoef.empty()) + mCoef.resize(1, (_T)0.0); + } + + /*! + * Create a vector of given order, with each coefficient + * set to zero + */ + OneD(size_t order) : + mCoef(order + 1, (_T)0.0) + { + } + + //! assignment operator + OneD& operator=(const OneD& o) + { + if (&o != this) + { + mCoef.clear(); + std::copy(o.mCoef.begin(), o.mCoef.end(), std::back_inserter(mCoef)); + } + return *this; + } + + /*! + * This function allows you to copy the values + * directly from a raw buffer. The first argument + * is the order, NOT THE NUMBER OF COEFFICIENTS. + * Therefore, you should always pass an array with + * one more element than the first argument + * + * The power coefficients are in ascending order + * (note that this is the reverse of Matlab) + * + * \param order The order of the polynomial + * \param The order + 1 coefficients to initialize + */ + OneD(size_t order, const _T* coef) + { + mCoef.resize(order + 1); + memcpy(&mCoef[0], coef, (order + 1) * sizeof(_T)); + } + + size_t order() const + { + if (empty()) + throw except::IndexOutOfRangeException( + Ctxt( + "Can't have an order less than zero")); + return mCoef.size() - 1; + } + + inline size_t size() const + { + return mCoef.size(); + } + + inline bool empty() const + { + return mCoef.empty(); + } + + _T operator ()(double at) const; + _T integrate(double start, double end) const; + OneD<_T>derivative() const; + _T& operator[](size_t i); + _T operator[](size_t i) const; + template + friend std::ostream& operator <<(std::ostream& out, const OneD<_TT>& p); + OneD<_T>& operator *=(double cv); + OneD<_T>operator *(double cv) const; + template + friend OneD<_TT>operator *(double cv, const OneD<_TT>& p); + OneD<_T>& operator *=(const OneD<_T>& p); + OneD<_T>operator *(const OneD<_T>& p) const; + OneD<_T>& operator +=(const OneD<_T>& p); + OneD<_T>operator +(const OneD<_T>& p) const; + OneD<_T>& operator -=(const OneD<_T>& p); + OneD<_T>operator -(const OneD<_T>& p) const; + OneD<_T>& operator /=(double cv); + OneD<_T>operator /(double cv) const; + + template bool operator==(const Vector_T& p) const + { + size_t sz = size(); + size_t psz = p.size(); + size_t minSize = std::min(sz, psz); + + // guard against uninitialized + if (minSize == 0 && (sz != psz)) + return false; + + for (size_t i = 0; i < minSize; i++) + if (!math::linear::equals(mCoef[i], p[i])) + return false; + + _T dflt(0.0); + + // Cover case where one polynomial has more + // coefficients than the other. + if (sz > psz) + { + for (size_t i = minSize; i < sz; i++) + if (!math::linear::equals(mCoef[i], dflt)) + return false; + } + else if (sz < psz) + { + for (size_t i = minSize; i < psz; i++) + if (!math::linear::equals(p[i], dflt)) + return false; + } + + return true; + } + + template bool operator!=(const Vector_T& p) const + { + return !(*this == p); + } +}; + +} // poly +} // math +#include "math/poly/OneD.hpp" +#endif diff --git a/modules/c++/math.poly/include/math/poly/OneD.hpp b/modules/c++/math.poly/include/math/poly/OneD.hpp new file mode 100644 index 000000000..17205a885 --- /dev/null +++ b/modules/c++/math.poly/include/math/poly/OneD.hpp @@ -0,0 +1,258 @@ +/* ========================================================================= + * This file is part of math.poly-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * math.poly-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include +#include +#include + +namespace math +{ +namespace poly +{ + +template +_T +OneD<_T>::operator () (double at) const +{ + _T ret(0.0); + double atPwr = 1.0; + for (size_t i = 0, sz = mCoef.size() ; i < sz; i++) + { + ret += mCoef[i]*atPwr; + atPwr *= at; + } + return ret; +} + +template +_T +OneD<_T>::integrate(double start, double end) const +{ + _T ret(0.0); + double endAtPwr = end; + double startAtPwr = start; + double div = 0; + double newCoef; + for (size_t i = 0, sz = mCoef.size(); i < sz; i++) + { + div = 1.0 / (i + 1); + newCoef = mCoef[i] * div; + ret += newCoef * endAtPwr; + ret -= newCoef * startAtPwr; + endAtPwr *= end; + startAtPwr *= start; + } + return ret; +} + +template +OneD<_T> +OneD<_T>::derivative() const +{ + OneD<_T> ret(0); + if (order() > 0) + { + ret = OneD<_T>(order()-1); + for (size_t ii = 0, sz = mCoef.size() - 1; ii < sz; ii++) + { + ret[ii] = static_cast<_T>(mCoef[ii + 1] * (ii + 1)); + } + } + return ret; +} + +template +_T& +OneD<_T>::operator [] (size_t i) +{ + if (i < mCoef.size()) + { + return (mCoef[i]); + } + else + { + std::stringstream str; + str << "index: " << i << " not within range [0..." + << mCoef.size() << ")"; + std::string msg(str.str()); + throw except::IndexOutOfRangeException(Ctxt(msg)); + } +} + + +template +_T +OneD<_T>::operator [] (size_t i) const +{ + _T ret(0.0); + if (i < mCoef.size()) + { + ret = mCoef[i]; + } + else + { + std::stringstream str; + str << "idx(" << i << ") not within range [0..." << mCoef.size() << ")"; + std::string msg(str.str()); + throw except::IndexOutOfRangeException(Ctxt(msg)); + } + return ret; +} + +template +std::ostream& +operator << (std::ostream& out, const OneD<_T>& p) +{ + for (size_t i = 0 ; i < p.mCoef.size() ; i++) + { + out << p[i] << "*y^" << i << " "; + } + return out; +} + +template +OneD<_T>& +OneD<_T>::operator *= (double cv) +{ + for (size_t i = 0, sz = mCoef.size() ; i < sz; i++) + { + mCoef[i] *= cv; + } + return *this; +} + +template +OneD<_T> +OneD<_T>::operator * (double cv) const +{ + OneD<_T> ret(*this); + ret *= cv; + return ret; +} + +template +OneD<_T> +operator * (double cv, const OneD<_T>& p) +{ + return p*cv; +} + +template +OneD<_T>& +OneD<_T>::operator *= (const OneD<_T>& p) +{ + OneD<_T> tmp(order()+p.order()); + for (size_t i = 0, xsz = mCoef.size() ; i < xsz; i++) + { + for (unsigned int j = 0, ysz = p.mCoef.size() ; j < ysz; j++) + { + tmp.mCoef[i + j] += mCoef[i] * p.mCoef[j]; + } + } + *this = tmp; + return *this; +} + +template +OneD<_T> +OneD<_T>::operator * (const OneD<_T>& p) const +{ + OneD<_T> ret(*this); + ret *= p; + return ret; +} + +template +OneD<_T>& +OneD<_T>::operator += (const OneD<_T>& p) +{ + OneD<_T> tmp(std::max(order(), p.order())); + for (size_t i = 0, sz = mCoef.size() ; i < sz; i++) + { + tmp.mCoef[i] = mCoef[i]; + } + for (size_t i = 0, sz = p.mCoef.size() ; i < sz; i++) + { + tmp.mCoef[i] += p.mCoef[i]; + } + *this = tmp; + return *this; +} + +template +OneD<_T> +OneD<_T>::operator + (const OneD<_T>& p) const +{ + OneD<_T> ret(*this); + ret += p; + return ret; +} + +template +OneD<_T>& +OneD<_T>::operator -= (const OneD<_T>& p) +{ + OneD<_T> tmp(std::max(order(), p.order())); + for (unsigned int i = 0, sz = mCoef.size() ; i < sz; i++) + { + tmp.mCoef[i] = mCoef[i]; + } + for (unsigned int i = 0, sz = p.mCoef.size(); i < sz; i++) + { + tmp.mCoef[i] -= p.mCoef[i]; + } + *this = tmp; + return *this; +} + +template +OneD<_T> +OneD<_T>::operator - (const OneD<_T>& p) const +{ + OneD<_T> ret(*this); + ret -= p; + return ret; +} + +template +OneD<_T>& +OneD<_T>::operator /= (double cv) +{ + double recipCV = 1.0/cv; + for (unsigned int i = 0, sz = mCoef.size() ; i < sz; i++) + { + mCoef[i] *= recipCV; + } + return *this; +} + +template +OneD<_T> +OneD<_T>::operator / (double cv) const +{ + OneD<_T> ret(*this); + ret *= (1.0/cv); + return ret; +} + +} // poly +} // math diff --git a/modules/c++/math.poly/include/math/poly/TwoD.h b/modules/c++/math.poly/include/math/poly/TwoD.h new file mode 100644 index 000000000..47717a076 --- /dev/null +++ b/modules/c++/math.poly/include/math/poly/TwoD.h @@ -0,0 +1,164 @@ +/* ========================================================================= + * This file is part of math.poly-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * math.poly-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ +#ifndef __MATH_POLY_TWOD_H__ +#define __MATH_POLY_TWOD_H__ + +#include "math/poly/OneD.h" +#include "math/linear/Matrix2D.h" + +namespace math +{ +namespace poly +{ +/*! This class defines an implementation for a 2-D polynomial. It should + support datatypes that allow the following operators: + _T(0), _T*_T, _T*=_T, _T+_T, _T+=_T, _T-_T, _T-=_T, -T* + + It supports polynomials of the form: + a00 + a01*x + a02*x^2 + ... + y*(a10 + a11*x + a12*x^2 + ...) + + It supports evaluating the integral over a specified interval (a...b, c...d) + + It supports computing the derivative + + And, it supports the multiplication/addtion/subtraction of 2-D polynomials. + + Also note: + In a 2-D sense, + X -> line + Y -> elem +*/ +template +class TwoD +{ +protected: + //! using a vector of one-d polynomials simplify the implementation. + std::vector > mCoef; + +public: + + std::vector >& coeffs(){ return mCoef; } + + //! The polynomial is invalid (i.e. orderX() and orderY() will throw) + TwoD() {} + + TwoD(size_t orderX, size_t orderY) : mCoef(orderX+1,OneD<_T>(orderY)) {} + + template TwoD(size_t orderX, size_t orderY, + const Vector_T& coeffs) + { + mCoef.resize(orderX+1,OneD<_T>(orderY)); + for (size_t i = 0; i <= orderX; ++i) + { + for (size_t j = 0; j <= orderY; ++j) + { + mCoef[i][j] = coeffs[i * (orderY+1) + j]; + } + } + } + bool empty() const + { + return mCoef.empty(); + } + size_t orderX() const + { + if (empty()) + throw except::IndexOutOfRangeException(Ctxt("Can't have an order less than zero")); + + return mCoef.size() - 1; + } + size_t orderY() const + { + if (empty()) + throw except::IndexOutOfRangeException(Ctxt("Can't have an order less than zero")); + return mCoef[0].order(); + } + _T operator () (double atX, double atY) const; + _T integrate(double xStart, double xEnd, double yStart, double yEnd) const; + + //! Must check the size of the OneD coming in because + // the dimensions of the TwoD is rigid, and all OneD + // polys must be of the same size + void set(size_t i, const OneD<_T>& p) + { + if (i > orderX()) + throw except::Exception( + Ctxt("Index [" + str::toString(i) + + "] is out of bounds for orderX [" + + str::toString(orderX()) + "]")); + else if (p.order() != orderY()) + throw except::Exception( + Ctxt("OneD poly [" + str::toString(p.order()) + + "] is of the incorrect size for orderY [" + + str::toString(orderY()) + "]")); + else + mCoef[i] = p; + } + + /*! + * Transposes the coefficients so that X is Y and Y is X + * + */ + TwoD<_T> flipXY() const; + TwoD<_T> derivativeY() const; + TwoD<_T> derivativeX() const; + TwoD<_T> derivativeXY() const; + /*! + * This evaluates y in the 2D polynomial, leaving a 1D polynomial in x + * That is, poly(x, y) == poly.atY(y)(x) + * If you want the equivalent of an atX() method so that you get a 1D + * polynomial in y, you can do poly.flipXY().atY(x) + */ + OneD<_T> atY(double y) const; + OneD<_T> operator [] (size_t i) const; + /*! In case you are curious about the return value, this guarantees that + someone can only change the coefficient stored at [x][y], and not the + polynomial itself. Unfortunately, however, it does not allow one bounds + checking on the size of the polynomial. + */ + _T* operator [] (size_t i); + TwoD<_T>& operator *= (double cv) ; + TwoD<_T> operator * (double cv) const; + template + friend TwoD<_TT> operator * (double cv, const TwoD<_TT>& p); + TwoD<_T>& operator *= (const TwoD<_T>& p); + TwoD<_T> operator * (const TwoD<_T>& p) const; + TwoD<_T>& operator += (const TwoD<_T>& p); + TwoD<_T> operator + (const TwoD<_T>& p) const; + TwoD<_T>& operator -= (const TwoD<_T>& p); + TwoD<_T> operator - (const TwoD<_T>& p) const; + TwoD<_T>& operator /= (double cv); + TwoD<_T> operator / (double cv) const; + bool operator == (const TwoD<_T>& p) const; + bool operator != (const TwoD<_T>& p) const; + + TwoD<_T> power(size_t toThe) const; + + template + friend std::ostream& operator << (std::ostream& out, const TwoD<_TT> p); +}; + +} // poly +} // math +#include "math/poly/TwoD.hpp" +#endif diff --git a/modules/c++/math.poly/include/math/poly/TwoD.hpp b/modules/c++/math.poly/include/math/poly/TwoD.hpp new file mode 100644 index 000000000..0b19cb9bd --- /dev/null +++ b/modules/c++/math.poly/include/math/poly/TwoD.hpp @@ -0,0 +1,404 @@ +/* ========================================================================= + * This file is part of math.poly-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * math.poly-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include +#include +#include "math/poly/OneD.h" + +namespace math +{ +namespace poly +{ + +template +_T +TwoD<_T>::operator () (double atX, double atY) const +{ + _T ret(0.0); + double atXPwr = 1.0; + for (size_t i = 0, sz = mCoef.size(); i < sz; i++) + { + ret += mCoef[i](atY) * atXPwr; + atXPwr *= atX; + } + return ret; +} + +template +_T +TwoD<_T>::integrate(double xStart, double xEnd, + double yStart, double yEnd) const +{ + _T ret(0.0); + double endAtPwr = xEnd; + double startAtPwr = xStart; + double div = 0; + double newCoef; + for (size_t i = 0, sz = mCoef.size(); i < sz; i++) + { + div = 1.0 / (i + 1); + newCoef = mCoef[i].integrate(yStart, yEnd) * div; + ret += newCoef * endAtPwr; + ret -= newCoef * startAtPwr; + endAtPwr *= xEnd; + startAtPwr *= xStart; + } + return ret; +} + +template +TwoD<_T> +TwoD<_T>::derivativeY() const +{ + TwoD<_T> ret(0, 0); + if ((orderY() > 0)) + { + ret = TwoD<_T>(orderX(), orderY()-1); + for (size_t i = 0 ; i < mCoef.size() ; i++) + { + ret.mCoef[i] = mCoef[i].derivative(); + } + } + return ret; +} + +template +TwoD<_T> +TwoD<_T>::derivativeX() const +{ + TwoD<_T> ret(0, 0); + if ((orderX() > 0)) + { + ret = TwoD<_T>(orderX()-1, orderY()); + for (size_t i = 0, sz = mCoef.size()-1; i < sz; i++) + { + ret.mCoef[i] = mCoef[i + 1] * (_T)(i+1); + } + } + return ret; +} + +template +OneD<_T> +TwoD<_T>::atY(double y) const +{ + OneD<_T> ret(0); + if (orderX() > 0) + { + // We have no more X, but we have Y still + ret = OneD<_T>(orderX()); + for (size_t i = 0; i < mCoef.size(); i++) + { + // Get me down to an X + ret[i] = mCoef[i](y); + } + } + return ret; +} + +template +TwoD<_T> +TwoD<_T>::power(size_t toThe) const +{ + // If its 0, we have to give back a 1*x^0*y^0 poly, since + // we want a 2D poly out + if (toThe == 0) + { + TwoD<_T> zero(0, 0); + zero[0][0] = 1; + return zero; + } + + TwoD rv = *this; + + // If its 1 give it back now + if (toThe == 1) + return rv; + + + // Otherwise, we have to raise it + for (size_t i = 2; i <= toThe; i++) + { + rv *= *this; + } + return rv; +} + + +template +TwoD<_T> +TwoD<_T>::flipXY() const +{ + size_t oY = orderX(); + size_t oX = orderY(); + TwoD<_T> prime(oX, oY); + + for (size_t i = 0; i <= oX; i++) + for (size_t j = 0; j <= oY; j++) + prime[i][j] = mCoef[j][i]; + return prime; +} + +template +TwoD<_T> +TwoD<_T>::derivativeXY() const +{ + TwoD<_T> ret = derivativeY().derivativeX(); + return ret; +} + +template +OneD<_T> +TwoD<_T>::operator [] (size_t i) const +{ + OneD<_T> ret(0); + if (i < mCoef.size()) + { + ret = mCoef[i]; + } + else + { + std::stringstream str; + str << "index:" << i << " not within range [0..." + << mCoef.size() << ")"; + + std::string msg(str.str()); + throw except::IndexOutOfRangeException(Ctxt(msg)); + } + return ret; +} + +template +_T* +TwoD<_T>::operator [] (size_t i) +{ + if (i < mCoef.size()) + { + return(&(mCoef[i][0])); + } + else + { + std::stringstream str; + str << "index: " << i << " not within range [0..." + << mCoef.size() << ")"; + std::string msg(str.str()); + throw(except::IndexOutOfRangeException(Ctxt(msg))); + } +} + +template +TwoD<_T>& +TwoD<_T>::operator *= (double cv) +{ + for (size_t i = 0, sz = mCoef.size(); i < sz; i++) + { + mCoef[i] *= cv; + } + return *this; +} + +template +TwoD<_T> +TwoD<_T>::operator * (double cv) const +{ + TwoD<_T> ret(*this); + ret *= cv; + return ret; +} + +template +TwoD<_T> +operator * (double cv, const TwoD<_T>& p) +{ + return p * cv; +} + +template +TwoD<_T>& +TwoD<_T>::operator *= (const TwoD<_T>& p) +{ + TwoD<_T> tmp(orderX() + p.orderX(), orderY() + p.orderY()); + for (int i = 0, xsz = mCoef.size() ; i < xsz; i++) + { + for (int j = 0, ysz = p.mCoef.size() ; j < ysz; j++) + { + tmp.mCoef[i + j] += mCoef[i] * p.mCoef[j]; + } + } + *this = tmp; + return *this; +} + +template +TwoD<_T> +TwoD<_T>::operator * (const TwoD<_T>& p) const +{ + TwoD<_T> ret(*this); + ret *= p; + return ret; +} + +template +TwoD<_T>& +TwoD<_T>::operator += (const TwoD<_T>& p) +{ + TwoD<_T> tmp(std::max(orderX(), p.orderX()), + std::max(orderY(), p.orderY())); + for (unsigned int i = 0, sz = mCoef.size() ; i < sz; i++) + { + tmp.mCoef[i] = mCoef[i]; + } + for (unsigned int i = 0, sz = p.mCoef.size() ; i < sz; i++) + { + tmp.mCoef[i] += p.mCoef[i]; + } + *this = tmp; + return *this; +} + +template +TwoD<_T> +TwoD<_T>::operator + (const TwoD<_T>& p) const +{ + TwoD<_T> ret(*this); + ret += p; + return ret; +} + +template +TwoD<_T>& +TwoD<_T>::operator-=(const TwoD<_T>& p) +{ + TwoD<_T> tmp(std::max(orderX() ,p.orderX()), + std::max(orderY(), p.orderY())); + + for (size_t i = 0, sz = mCoef.size() ; i < sz; i++) + { + tmp.mCoef[i] = mCoef[i]; + } + + for (size_t i = 0, sz = p.mCoef.size() ; i < sz; i++) + { + tmp.mCoef[i] -= p.mCoef[i]; + } + + *this = tmp; + return *this; +} + +template +TwoD<_T> +TwoD<_T>::operator-(const TwoD<_T>& p) const +{ + TwoD<_T> ret(*this); + ret -= p; + return ret; +} + +template +TwoD<_T>& +TwoD<_T>::operator/=(double cv) +{ + double recipCV = 1.0/cv; + for (size_t i = 0, sz = mCoef.size() ; i < sz; i++) + { + mCoef[i] *= recipCV; + } + return *this; +} + +template +TwoD<_T> +TwoD<_T>::operator/(double cv) const +{ + TwoD<_T> ret(*this); + ret *= (1.0/cv); + return ret; +} + +template +std::ostream& +operator << (std::ostream& out, const TwoD<_T> p) +{ + for (size_t i = 0 ; i < p.mCoef.size() ; i++) + { + out << "x^" << i << "*(" << p[i] << ")" << std::endl; + } + return out; +} + +template +bool +TwoD<_T>::operator == (const TwoD<_T>& p) const +{ + size_t sz = mCoef.size(); + size_t psz = p.mCoef.size(); + size_t minSize = std::min(sz, psz); + + // guard against uninitialized + if (minSize == 0 && (sz != psz)) + return false; + + for (size_t i = 0 ; i < minSize ; i++) + { + if (mCoef[i] != p.mCoef[i]) + return false; + } + + // Cover case where one polynomial has more coefficients than the other. + if (sz > psz) + { + OneD<_T> dflt(orderY()); + + for (size_t ii = minSize ; ii < sz; ++ii) + { + if (mCoef[ii] != dflt) + { + return false; + } + } + } + else if (sz < psz) + { + OneD<_T> dflt(p.orderY()); + + for (size_t ii = minSize ; ii < psz ; ++ii) + { + if (p.mCoef[ii] != dflt) + { + return false; + } + } + } + + return true; +} + +template +bool +TwoD<_T>::operator != (const TwoD<_T>& p) const +{ + return !(*this == p); +} + +} // poly +} // math diff --git a/modules/c++/math.poly/tests/test_fixed.cpp b/modules/c++/math.poly/tests/test_fixed.cpp new file mode 100644 index 000000000..ea28fffc6 --- /dev/null +++ b/modules/c++/math.poly/tests/test_fixed.cpp @@ -0,0 +1,188 @@ +/* ========================================================================= + * This file is part of math.poly-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * math.poly-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ +#include + +using namespace math::poly; + +typedef Fixed1D<1> Linear1D; +typedef Fixed1D<2> Quadratic1D; +typedef Fixed1D<3> Cubic1D; +typedef Fixed1D<4> Quartic1D; + +typedef Fixed2D<1, 1> Linear2D; +typedef Fixed2D<2, 2> Quadratic2D; +typedef Fixed2D<3, 3> Cubic2D; +typedef Fixed2D<4, 4> Quartic2D; + + +int main(int argc, char* argv[]) +{ + // first, lets do a one-d polynomial test... + Cubic1D lOneDTst; + lOneDTst[0] = -3; + lOneDTst[1] = 1; + lOneDTst[2] = 2; + std::cout << "Test 1-D Polynomial implementation..." << std::endl; + std::cout << "lOneDTstPoly: " << lOneDTst << std::endl; + std::cout << "lOneDTst(" << (-1) << ") = " << lOneDTst(-1) << std::endl; + std::cout << "lOneDTst(" << (-.5) << ") = " << lOneDTst(-.5) << std::endl; + std::cout << "lOneDTst(" << (0) << ") = " << lOneDTst(0) << std::endl; + std::cout << "lOneDTst(" << (.5) << ") = " << lOneDTst(.5) << std::endl; + std::cout << "lOneDTst(" << (1) << ") = " << lOneDTst(1) << std::endl; + std::cout << std::endl; + std::cout << "Test 1-D Polynomial Derivative implemenation..." << std::endl; + std::cout << "lOneDTstPoly: " << lOneDTst.derivative() << std::endl; + std::cout << std::endl; + std::cout << "Test 1-D Polynomial Integral implementation..." << std::endl; + Quadratic1D lDeriv(lOneDTst.derivative()); + std::cout << "Integrate: " << lDeriv << " over the interval from -1 to 1" << std::endl; + std::cout << "Integral(-1,1) = " << lDeriv.integrate(-1,1) << std::endl; + + std::cout << "Expected Res = " << lOneDTst(1)-lOneDTst(-1) << std::endl; + + std::cout << "Test 1-D Polynomial * implementation..." << std::endl; + Linear1D lOneDTst2; + lOneDTst2[0] = 1; + lOneDTst2[1] = 1; + std::cout << "lOneDTstPoly: " << lOneDTst2 << std::endl; + std::cout << "lOneDTstPoly^2: " << lOneDTst2*lOneDTst2 << std::endl; + std::cout << std::endl; + + std::cout << "Test 1-D Polynomial + implementation..." << std::endl; + std::cout << "lOneDTstPoly1: " << lOneDTst << std::endl; + std::cout << "lOneDTstPoly2: " << lOneDTst2 << std::endl; + Quadratic1D plus = lOneDTst2 + lOneDTst; + + std::cout << "lOneDTstPoly2 + lOneDTstPoly1 (quad): " << plus << std::endl; + std::cout << "lOneDTstPoly2 + lOneDTstPoly1: " << lOneDTst2 + lOneDTst << std::endl; + std::cout << std::endl; + + std::cout << "Test 1-D Polynomial - implementation..." << std::endl; + + std::cout << "lOneDTstPoly1: " << lOneDTst << std::endl; + std::cout << "N: " << lOneDTst * -1 << std::endl; + std::cout << "lOneDTstPoly2: " << lOneDTst2 << std::endl; + plus = lOneDTst2-lOneDTst; + std::cout << "lOneDTstPoly2 - lOneDTstPoly1 (quad): " << plus << std::endl; + std::cout << "lOneDTstPoly2 - lOneDTstPoly1: " << lOneDTst2-lOneDTst << std::endl; + std::cout << std::endl; + + + // now, lets do a two-d polynomial test... + Fixed2D<3, 1, double> lTwoDTst; + lTwoDTst[0][0] = -3; + lTwoDTst[0][1] = 1; + lTwoDTst[1][0] = -1; + lTwoDTst[1][1] = 0; + lTwoDTst[2][0] = -2; + lTwoDTst[2][1] = -1; + std::cout << "Test 2-D Polynomial implementation..." << std::endl; + std::cout << "lTwoDTstPoly: " << std::endl << lTwoDTst << std::endl; + std::cout << "lTwoDTst(" << 0 << "," << 0 << ") = " << lTwoDTst(0,0) << std::endl; + std::cout << "lTwoDTst(" << 0 << "," << 2 << ") = " << lTwoDTst(0,2) << std::endl; + std::cout << "lTwoDTst(" << 2 << "," << 0 << ") = " << lTwoDTst(2,0) << std::endl; + std::cout << "lTwoDTst(" << 2 << "," << -2 << ") = " << lTwoDTst(2,-2) << std::endl; + std::cout << std::endl; + + + std::cout << "Test 2-D Polynomial atX implementation..." << std::endl; + std::cout << "lTwoDTstPoly: " << std::endl << lTwoDTst << std::endl; + + math::poly::Fixed1D<3> lAt = lTwoDTst.atY(2); + + std::cout << "lAt(" << 2 << ") = " << lAt << std::endl; + std::cout << std::endl; + + + + std::cout << "Test 2-D Polynomial DerivativeY implementation..." << std::endl; + std::cout << "lTwoDTstPoly: " << lTwoDTst.derivativeY() << std::endl; + std::cout << std::endl; + /*try + { + std::cout << "Test 2-D Polynomial DerivativeY.DerivativeY implementation..." << std::endl; + std::cout << "lTwoDTstPoly: " << lTwoDTst.derivativeY().derivativeY() << std::endl; + std::cout << std::endl; + } + catch (except::Exception& ex) + { + std::cout << ex.getMessage() << std::endl; + }*/ + + std::cout << "Test 2-D Polynomial DerivativeX implementation..." << std::endl; + std::cout << "lTwoDTstPoly: " << lTwoDTst.derivativeX() << std::endl; + std::cout << std::endl; + std::cout << "Test 2-D Polynomial DerivativeX.DerivativeX implementation..." << std::endl; + std::cout << "lTwoDTstPoly: " << lTwoDTst.derivativeX().derivativeX() << std::endl; + std::cout << std::endl; + std::cout << "Test 2-D Polynomial DerivativeXY implementation..." << std::endl; + std::cout << "lTwoDTstPoly: " << lTwoDTst.derivativeXY() << std::endl; + std::cout << std::endl; + std::cout << "Test 2-D Polynomial DerivativeXY.DerivativeXY implemenation..." << std::endl; + /*try + { + std::cout << "lTwoDTstPoly: " << lTwoDTst.derivativeXY().derivativeXY() << std::endl; + std::cout << std::endl; + } + catch (except::Exception& ex) + { + std::cout << ex.getMessage() << std::endl; + }*/ + std::cout << "Test 2-D Polynomial Integral implementation..." << std::endl; + math::poly::Fixed2D<2, 0, double> lDeriv2(lTwoDTst.derivativeXY()); + std::cout << "Integrate: " << lDeriv2 << " over the interval... " << std::endl; + std::cout << "Integral(-2,3,-1,2) = " << lDeriv2.integrate(-2,3,-1,2) << std::endl; + std::cout << "Expected Res = " << (lTwoDTst(3,2)-lTwoDTst(3,-1))-(lTwoDTst(-2,2)-lTwoDTst(-2,-1)) << std::endl; + + std::cout << "Test 2-D Polynomial * implementation..." << std::endl; + + Fixed2D<2, 1> lTwoDTst2; + lTwoDTst2[0][0] = 1; + lTwoDTst2[0][1] = 1; + lTwoDTst2[1][0] = -1; + lTwoDTst2[1][1] = 2; + std::cout << "lTwoDTstPoly: " << lTwoDTst << std::endl; + std::cout << "lTwoDTstPoly2: " << lTwoDTst2 << std::endl; + + std::cout << "lTwoDTstPoly*lTwoDTstPoly2: " << lTwoDTst*lTwoDTst2 << std::endl; + std::cout << std::endl; + + std::cout << "Test 2-D Polynomial + implementation..." << std::endl; + std::cout << "lTwoDTstPoly1: " << lTwoDTst << std::endl; + std::cout << "lTwoDTstPoly2: " << lTwoDTst2 << std::endl; + Fixed2D<3, 1> mix = lTwoDTst2+lTwoDTst; + + std::cout << "lTwoDTstPoly2 + lTwoDTstPoly1: (cubic) " << mix << std::endl; + std::cout << "lTwoDTstPoly2 + lTwoDTstPoly1: " << lTwoDTst2+lTwoDTst << std::endl; + std::cout << std::endl; + + + std::cout << "Test 2-D Polynomial - implementation..." << std::endl; + std::cout << "lTwoDTstPoly1: " << lTwoDTst << std::endl; + std::cout << "lTwoDTstPoly2: " << lTwoDTst2 << std::endl; + mix = lTwoDTst2-lTwoDTst; + + std::cout << "lOneDTstPoly2 - lOneDTstPoly1: (cubic) " << mix << std::endl; + + std::cout << "lOneDTstPoly2 - lOneDTstPoly1: " << lTwoDTst2-lTwoDTst << std::endl; + std::cout << std::endl; +} diff --git a/modules/c++/math.poly/tests/test_inner_poly.cpp b/modules/c++/math.poly/tests/test_inner_poly.cpp new file mode 100644 index 000000000..dc8be7b53 --- /dev/null +++ b/modules/c++/math.poly/tests/test_inner_poly.cpp @@ -0,0 +1,80 @@ +/* ========================================================================= + * This file is part of math.poly-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * math.poly-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include +using namespace math::poly; + +TwoDcascade(TwoDoldP, TwoDgx, TwoDgy) +{ + + TwoDnewP(oldP.orderX(), oldP.orderY()); + + for (size_t i = 0; i <= oldP.orderX(); i++) + { + for (size_t j = 0; j <= oldP.orderY(); j++) + { + newP += (gx.power(i) * (gy.power(j) * oldP[i][j])); + } + } + + return newP; +} + +int main() +{ + + try + { + TwoDf(1, 1); + // 5 + xy + f[0][0] = 5; + f[1][1] = 1; + + std::cout << "f(x, y):" << std::endl << f << std::endl; + TwoDh(2, 2); + h[0][0] = 6; + h[1][2] = 3; + std::cout << "h(x, y)" << std::endl << h << std::endl; + + TwoDgx(1, 1); + gx[0][1] = gx[1][0] = 1; + std::cout << "gx(x, y):" << std::endl << gx << std::endl; + + TwoDgy(2, 2); + gy[2][0] = 1; + std::cout << "gy(x, y):" << std::endl << gy << std::endl; + + TwoDfp = cascade(f, gx, gy); + + std::cout << "fp(x, y):" << std::endl << fp << std::endl; + + TwoDhp = cascade(h, gx, gy); + + std::cout << "hp(x, y):" << std::endl << hp << std::endl; + + } + catch (except::Exception& ex) + { + std::cout << "Exception: " << ex.toString() << std::endl; + } + return 0; +} diff --git a/modules/c++/math.poly/tests/test_poly.cpp b/modules/c++/math.poly/tests/test_poly.cpp new file mode 100644 index 000000000..9537d86f8 --- /dev/null +++ b/modules/c++/math.poly/tests/test_poly.cpp @@ -0,0 +1,185 @@ +/* ========================================================================= + * This file is part of math.poly-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * math.poly-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include + +int main(int argc, char* argv[]) +{ + // first, lets do a one-d polynomial test... + math::poly::OneD lOneDTst(3); + lOneDTst[0] = -3; + lOneDTst[1] = 1; + lOneDTst[2] = 2; + std::cout << "Test 1-D Polynomial implementation..." << std::endl; + std::cout << "lOneDTstPoly: " << lOneDTst << std::endl; + std::cout << "lOneDTst(" << (-1) << ") = " << lOneDTst(-1) << std::endl; + std::cout << "lOneDTst(" << (-.5) << ") = " << lOneDTst(-.5) << std::endl; + std::cout << "lOneDTst(" << (0) << ") = " << lOneDTst(0) << std::endl; + std::cout << "lOneDTst(" << (.5) << ") = " << lOneDTst(.5) << std::endl; + std::cout << "lOneDTst(" << (1) << ") = " << lOneDTst(1) << std::endl; + std::cout << std::endl; + std::cout << "Test 1-D Polynomial Derivative implementation..." << std::endl; + std::cout << "lOneDTstPoly: " << lOneDTst.derivative() << std::endl; + std::cout << std::endl; + std::cout << "Test 1-D Polynomial Integral implementation..." << std::endl; + math::poly::OneD lDeriv(lOneDTst.derivative()); + std::cout << "Integrate: " << lDeriv << " over the interval from -1 to 1" << std::endl; + std::cout << "Integral(-1,1) = " << lDeriv.integrate(-1,1) << std::endl; + std::cout << "Expected Res = " << lOneDTst(1)-lOneDTst(-1) << std::endl; + + std::cout << "Test 1-D Polynomial * implementation..." << std::endl; + math::poly::OneD lOneDTst2(1); + lOneDTst2[0] = 1; + lOneDTst2[1] = 1; + std::cout << "lOneDTstPoly: " << lOneDTst2 << std::endl; + std::cout << "lOneDTstPoly^2: " << lOneDTst2*lOneDTst2 << std::endl; + std::cout << std::endl; + + std::cout << "Test 1-D Polynomial + implementation..." << std::endl; + std::cout << "lOneDTstPoly1: " << lOneDTst << std::endl; + std::cout << "lOneDTstPoly2: " << lOneDTst2 << std::endl; + std::cout << "lOneDTstPoly2 + lOneDTstPoly1: " << lOneDTst2+lOneDTst << std::endl; + std::cout << std::endl; + + std::cout << "Test 1-D Polynomial - implementation..." << std::endl; + std::cout << "lOneDTstPoly1: " << lOneDTst << std::endl; + std::cout << "lOneDTstPoly2: " << lOneDTst2 << std::endl; + std::cout << "lOneDTstPoly2 - lOneDTstPoly1: " << lOneDTst2-lOneDTst << std::endl; + std::cout << std::endl; + + math::poly::OneD lOneDTst3(5); + lOneDTst3[0] = lOneDTst[0]; + lOneDTst3[1] = lOneDTst[1]; + lOneDTst3[2] = lOneDTst[2]; + lOneDTst3[3] = 0.0; + lOneDTst3[4] = 0.0; + + std::cout << "Test 1-D Polynomial == implementation..." << std::endl; + std::cout << "lOneDTstPoly1: " << lOneDTst << std::endl; + std::cout << "lOneDTstPoly2: " << lOneDTst2 << std::endl; + std::cout << "lOneDTstPoly3: " << lOneDTst3 << std::endl; + std::cout << "lOneDTstPoly1 == lOneDTstPoly1: " << (int) (lOneDTst==lOneDTst) << std::endl; + std::cout << "lOneDTstPoly1 == lOneDTstPoly2: " << (int) (lOneDTst==lOneDTst2) << std::endl; + std::cout << "lOneDTstPoly1 == lOneDTstPoly3: " << (int) (lOneDTst==lOneDTst3) << std::endl; + std::cout << "lOneDTstPoly2 == lOneDTstPoly1: " << (int) (lOneDTst2==lOneDTst) << std::endl; + std::cout << "lOneDTstPoly2 == lOneDTstPoly3: " << (int) (lOneDTst2==lOneDTst3) << std::endl; + std::cout << "lOneDTstPoly3 == lOneDTstPoly: " << (int) (lOneDTst3==lOneDTst) << std::endl; + std::cout << "lOneDTstPoly3 == lOneDTstPoly2: " << (int) (lOneDTst3==lOneDTst2) << std::endl; + + // now, lets do a two-d polynomial test... + math::poly::TwoD lTwoDTst(3, 1); + lTwoDTst[0][0] = -3; + lTwoDTst[0][1] = 1; + lTwoDTst[1][0] = -1; + lTwoDTst[1][1] = 0; + lTwoDTst[2][0] = -2; + lTwoDTst[2][1] = -1; + std::cout << "Test 2-D Polynomial implementation..." << std::endl; + std::cout << "lTwoDTstPoly: " << std::endl << lTwoDTst << std::endl; + std::cout << "lTwoDTst(" << 0 << "," << 0 << ") = " << lTwoDTst(0,0) << std::endl; + std::cout << "lTwoDTst(" << 0 << "," << 2 << ") = " << lTwoDTst(0,2) << std::endl; + std::cout << "lTwoDTst(" << 2 << "," << 0 << ") = " << lTwoDTst(2,0) << std::endl; + std::cout << "lTwoDTst(" << 2 << "," << -2 << ") = " << lTwoDTst(2,-2) << std::endl; + std::cout << std::endl; + + + std::cout << "Test 2-D Polynomial atX implementation..." << std::endl; + std::cout << "lTwoDTstPoly: " << std::endl << lTwoDTst << std::endl; + + math::poly::OneD lAt = lTwoDTst.atY(2); + + std::cout << "lAt(" << 2 << ") = " << lAt << std::endl; + std::cout << std::endl; + + + + std::cout << "Test 2-D Polynomial DerivativeY implementation..." << std::endl; + std::cout << "lTwoDTstPoly: " << lTwoDTst.derivativeY() << std::endl; + std::cout << std::endl; + std::cout << "Test 2-D Polynomial DerivativeY.DerivativeY implementation..." << std::endl; + std::cout << "lTwoDTstPoly: " << lTwoDTst.derivativeY().derivativeY() << std::endl; + std::cout << std::endl; + std::cout << "Test 2-D Polynomial DerivativeX implementation..." << std::endl; + std::cout << "lTwoDTstPoly: " << lTwoDTst.derivativeX() << std::endl; + std::cout << std::endl; + std::cout << "Test 2-D Polynomial DerivativeX.DerivativeX implementation..." << std::endl; + std::cout << "lTwoDTstPoly: " << lTwoDTst.derivativeX().derivativeX() << std::endl; + std::cout << std::endl; + std::cout << "Test 2-D Polynomial DerivativeXY implementation..." << std::endl; + std::cout << "lTwoDTstPoly: " << lTwoDTst.derivativeXY() << std::endl; + std::cout << std::endl; + std::cout << "Test 2-D Polynomial DerivativeXY.DerivativeXY implementation..." << std::endl; + std::cout << "lTwoDTstPoly: " << lTwoDTst.derivativeXY().derivativeXY() << std::endl; + std::cout << std::endl; + + std::cout << "Test 2-D Polynomial Integral implementation..." << std::endl; + math::poly::TwoD lDeriv2(lTwoDTst.derivativeXY()); + std::cout << "Integrate: " << lDeriv2 << " over the interval... " << std::endl; + std::cout << "Integral(-2,3,-1,2) = " << lDeriv2.integrate(-2,3,-1,2) << std::endl; + std::cout << "Expected Res = " << (lTwoDTst(3,2)-lTwoDTst(3,-1))-(lTwoDTst(-2,2)-lTwoDTst(-2,-1)) << std::endl; + + std::cout << "Test 2-D Polynomial * implementation..." << std::endl; + math::poly::TwoD lTwoDTst2(2,1); + lTwoDTst2[0][0] = 1; + lTwoDTst2[0][1] = 1; + lTwoDTst2[1][0] = -1; + lTwoDTst2[1][1] = 2; + std::cout << "lTwoDTstPoly: " << lTwoDTst << std::endl; + std::cout << "lTwoDTstPoly2: " << lTwoDTst2 << std::endl; + std::cout << "lTwoDTstPoly*lTwoDTstPoly2: " << lTwoDTst*lTwoDTst2 << std::endl; + std::cout << std::endl; + + std::cout << "Test 2-D Polynomial + implementation..." << std::endl; + std::cout << "lTwoDTstPoly1: " << lTwoDTst << std::endl; + std::cout << "lTwoDTstPoly2: " << lTwoDTst2 << std::endl; + std::cout << "lTwoDTstPoly2 + lTwoDTstPoly1: " << lTwoDTst2+lTwoDTst << std::endl; + std::cout << std::endl; + + std::cout << "Test 2-D Polynomial - implementation..." << std::endl; + std::cout << "lTwoDTstPoly1: " << lTwoDTst << std::endl; + std::cout << "lTwoDTstPoly2: " << lTwoDTst2 << std::endl; + std::cout << "lOneDTstPoly2 - lOneDTstPoly1: " << lTwoDTst2-lTwoDTst << std::endl; + std::cout << std::endl; + + math::poly::TwoD lTwoDTst3(4,1); + lTwoDTst3[0][0] = lTwoDTst2[0][0]; + lTwoDTst3[0][1] = lTwoDTst2[0][1]; + lTwoDTst3[1][0] = lTwoDTst2[1][0]; + lTwoDTst3[1][1] = lTwoDTst2[1][1]; + + std::cout << "Test 2-D Polynomial == implementation..." << std::endl; + std::cout << "lTwoDTstPoly1: " << lTwoDTst << std::endl; + std::cout << "lTwoDTstPoly2: " << lTwoDTst2 << std::endl; + std::cout << "lTwoDTstPoly3: " << lTwoDTst3 << std::endl; + std::cout << "lTwoDTstPoly1 == lTwoDTstPoly1: " << (int) (lTwoDTst==lTwoDTst) << std::endl; + std::cout << "lTwoDTstPoly1 == lTwoDTstPoly2: " << (int) (lTwoDTst==lTwoDTst2) << std::endl; + std::cout << "lTwoDTstPoly1 == lTwoDTstPoly3: " << (int) (lTwoDTst==lTwoDTst3) << std::endl; + std::cout << "lTwoDTstPoly2 == lTwoDTstPoly1: " << (int) (lTwoDTst2==lTwoDTst) << std::endl; + std::cout << "lTwoDTstPoly2 == lTwoDTstPoly3: " << (int) (lTwoDTst2==lTwoDTst3) << std::endl; + std::cout << "lTwoDTstPoly3 == lTwoDTstPoly1: " << (int) (lTwoDTst3==lTwoDTst) << std::endl; + std::cout << "lTwoDTstPoly3 == lTwoDTstPoly2: " << (int) (lTwoDTst3==lTwoDTst2) << std::endl; + + math::poly::TwoD lundefTwoD1(0, 0); + math::poly::TwoD lundefTwoD2(0, 0); + std::cout << "lundefTwoD1 == lundefTwoD1: " << (int) (lundefTwoD1==lundefTwoD1) << std::endl; + std::cout << "lundefTwoD1 == lundefTwoD2: " << (int) (lundefTwoD1==lundefTwoD2) << std::endl; +} diff --git a/modules/c++/math.poly/unittests/test_llsq.cpp b/modules/c++/math.poly/unittests/test_llsq.cpp new file mode 100644 index 000000000..b413572d8 --- /dev/null +++ b/modules/c++/math.poly/unittests/test_llsq.cpp @@ -0,0 +1,98 @@ +/* ========================================================================= + * This file is part of math.poly-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * math.poly-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include +#include +#include "TestCase.h" + +using namespace math::linear; +using namespace math::poly; + +TEST_CASE(test1DPolyfit) +{ + double x_obs[] = { 1, -1, 2, -2 }; + double y_obs[] = { 3, 13, 1, 33 }; + double z_poly[] = { 5, -4, 3, -1 }; + + std::vector truthSTLVec(4); + memcpy(&truthSTLVec[0], z_poly, sizeof(double)*4); + + OneD truth(3, z_poly); + // First test the raw pointer signature + OneD polyFromRaw = fit(4, x_obs, y_obs, 3); + + // Now call the other one + Vector xv(4, x_obs); + Vector yv(4, y_obs); + + OneD polyFromVec = fit(xv, yv, 3); + + Fixed1D<3> fixed = fit(xv, yv, 3); + + OneD polyFromSTL(truthSTLVec); + + // Polys better match + TEST_ASSERT_EQ(polyFromRaw, polyFromVec); + TEST_ASSERT_EQ(polyFromRaw, truth); + TEST_ASSERT_EQ(polyFromRaw, fixed); + assert(polyFromRaw == truthSTLVec); + TEST_ASSERT_EQ(polyFromSTL, truth); + + +} + +TEST_CASE(test2DPolyfit) +{ + double coeffs[] = + { + -1.02141e-16, 0.15, + 0.08, 0.4825, + }; + + TwoD truth(1, 1, coeffs); + + Matrix2D x(3, 3); + x(0, 0) = 1; x(1, 0) = 0; x(2, 0) = 1; + x(0, 1) = 1; x(1, 1) = 1; x(2, 1) = 0; + x(0, 2) = 0; x(1, 2) = 1; x(2, 2) = 1; + + Matrix2D y(3, 3); + y(0, 0) = 1; y(1, 0) = 1; y(2, 0) = 1; + y(0, 1) = 0; y(1, 1) = 1; y(2, 1) = 1; + y(0, 2) = 0; y(1, 2) = 0; y(2, 2) = 1; + + + Matrix2D z(3, 3); + z(0, 0) = 1; z(1, 0) = .3; z(2, 0) = 0; + z(0, 1) = .16; z(1, 1) = 1; z(2, 1) = 0; + z(0, 2) = 0; z(1, 2) = 0; z(2, 2) = .85; + + TwoD poly = fit(x, y, z, 1, 1); + TEST_ASSERT_EQ(poly, truth); +} + +int main(int argc, char* argv[]) +{ + + TEST_CHECK(test1DPolyfit); + TEST_CHECK(test2DPolyfit); +} diff --git a/modules/c++/math.poly/wscript b/modules/c++/math.poly/wscript new file mode 100644 index 000000000..4286271af --- /dev/null +++ b/modules/c++/math.poly/wscript @@ -0,0 +1,9 @@ +NAME = 'math.poly' +MAINTAINER = 'jmrandol@users.sourceforge.net' +VERSION = '0.2' +MODULE_DEPS = 'sys math.linear' + +options = configure = distclean = lambda p: None + +def build(bld): + bld.module(**globals()) diff --git a/modules/c++/mem/include/import/mem.h b/modules/c++/mem/include/import/mem.h new file mode 100644 index 000000000..52a54e9b7 --- /dev/null +++ b/modules/c++/mem/include/import/mem.h @@ -0,0 +1,33 @@ +/* ========================================================================= + * This file is part of mem-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * mem-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __IMPORT_MEM_H__ +#define __IMPORT_MEM_H__ + +#include +#include +#include +#include +#include +#include + +#endif diff --git a/modules/c++/mem/include/mem/ScopedAlignedArray.h b/modules/c++/mem/include/mem/ScopedAlignedArray.h new file mode 100644 index 000000000..0b2047318 --- /dev/null +++ b/modules/c++/mem/include/mem/ScopedAlignedArray.h @@ -0,0 +1,115 @@ +/* ========================================================================= + * This file is part of mem-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * mem-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __MEM_SCOPED_ALIGNED_ARRAY_H__ +#define __MEM_SCOPED_ALIGNED_ARRAY_H__ + +#include + +#include + +namespace mem +{ + /*! + * \class ScopedAlignedArray + * \brief This class provides RAII for alignedAlloc() and alignedFree() + */ + template + class ScopedAlignedArray + { + public: + typedef T ElementType; + + explicit ScopedAlignedArray(size_t numElements = 0) : + mArray(allocate(numElements)) + { + } + + ~ScopedAlignedArray() + { + if (mArray) + { + // Don't expect sys::alignedFree() would ever throw, but just + // in case... + try + { + sys::alignedFree(mArray); + } + catch (...) + { + } + } + } + + void reset(size_t numElements = 0) + { + if (mArray) + { + sys::alignedFree(mArray); + mArray = NULL; + } + + mArray = allocate(numElements); + } + + T& operator[](std::ptrdiff_t idx) const + { + return mArray[idx]; + } + + T* get() const + { + return mArray; + } + + T* release() + { + T* const array = mArray; + mArray = NULL; + return array; + } + + private: + // Noncopyable + ScopedAlignedArray(const ScopedAlignedArray& ); + const ScopedAlignedArray& operator=(const ScopedAlignedArray& ); + + static + T* allocate(size_t numElements) + { + if (numElements > 0) + { + const size_t numBytes(numElements * sizeof(T)); + return static_cast(sys::alignedAlloc(numBytes)); + } + else + { + return NULL; + } + } + + private: + T* mArray; + }; +} + +#endif diff --git a/modules/c++/mem/include/mem/ScopedArray.h b/modules/c++/mem/include/mem/ScopedArray.h new file mode 100644 index 000000000..ca9dffa74 --- /dev/null +++ b/modules/c++/mem/include/mem/ScopedArray.h @@ -0,0 +1,84 @@ +/* ========================================================================= + * This file is part of mem-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * mem-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __MEM_SCOPED_ARRAY_H__ +#define __MEM_SCOPED_ARRAY_H__ + +#include + +namespace mem +{ + /*! + * \class ScopedArray + * \brief This class provides RAII for array allocations via new[]. + * It is based on boost::scoped_array. + */ + template + class ScopedArray + { + public: + typedef T ElementType; + + explicit ScopedArray(T* array = NULL) : + mArray(array) + { + } + + ~ScopedArray() + { + delete[] mArray; + } + + void reset(T* array = NULL) + { + delete[] mArray; + mArray = array; + } + + T& operator[](std::ptrdiff_t idx) const + { + return mArray[idx]; + } + + T* get() const + { + return mArray; + } + + T* release() + { + T* const array = mArray; + mArray = NULL; + return array; + } + + private: + // Noncopyable + ScopedArray(const ScopedArray& ); + const ScopedArray& operator=(const ScopedArray& ); + + private: + T* mArray; + }; +} + +#endif diff --git a/modules/c++/mem/include/mem/ScopedCloneablePtr.h b/modules/c++/mem/include/mem/ScopedCloneablePtr.h new file mode 100644 index 000000000..562303749 --- /dev/null +++ b/modules/c++/mem/include/mem/ScopedCloneablePtr.h @@ -0,0 +1,110 @@ +/* ========================================================================= + * This file is part of mem-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * mem-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __MEM_SCOPED_CLONEABLE_PTR_H__ +#define __MEM_SCOPED_CLONEABLE_PTR_H__ + +#include +#include + +namespace mem +{ +/*! + * \class ScopedCloneablePtr + * \brief This class provides RAII for object allocations via new. It is a + * light wrapper around std::auto_ptr and has the same semantics + * except that the copy constructor and assignment operator are deep + * copies (by using T's clone() method) rather than transferring + * ownership. + * + * This is useful for cases where you have a class which has a member + * variable that's dynamically allocated and you want to provide a + * valid copy constructor / assignment operator. With raw pointers or + * std::auto_ptr's, you'll have to write the copy constructor / + * assignment operator for this class - this is tedious and + * error-prone since you need to include all the members in the class. + * Using ScopedCloneablePtr's instead, the compiler-generated copy + * constructor and assignment operator for your class will be correct + * (if all the other member variables are POD or have correct + * copy constructors / assignment operators). + */ +template +class ScopedCloneablePtr +{ +public: + explicit ScopedCloneablePtr(T* ptr = NULL) + : mPtr(ptr) + { + } + + ScopedCloneablePtr(const ScopedCloneablePtr& rhs) + { + if (rhs.mPtr.get()) + { + mPtr.reset(rhs.mPtr->clone()); + } + } + + const ScopedCloneablePtr& + operator=(const ScopedCloneablePtr& rhs) + { + if (this != &rhs) + { + if (rhs.mPtr.get()) + { + mPtr.reset(rhs.mPtr->clone()); + } + else + { + mPtr.reset(); + } + } + + return *this; + } + + T* get() const + { + return mPtr.get(); + } + + T& operator*() const + { + return *mPtr; + } + + T* operator->() const + { + return mPtr.get(); + } + + void reset(T* ptr = NULL) + { + mPtr.reset(ptr); + } + +private: + std::auto_ptr mPtr; +}; +} + +#endif diff --git a/modules/c++/mem/include/mem/ScopedCopyablePtr.h b/modules/c++/mem/include/mem/ScopedCopyablePtr.h new file mode 100644 index 000000000..2690eeaa7 --- /dev/null +++ b/modules/c++/mem/include/mem/ScopedCopyablePtr.h @@ -0,0 +1,110 @@ +/* ========================================================================= + * This file is part of mem-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * mem-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __MEM_SCOPED_COPYABLE_PTR_H__ +#define __MEM_SCOPED_COPYABLE_PTR_H__ + +#include +#include + +namespace mem +{ +/*! + * \class ScopedCopyablePtr + * \brief This class provides RAII for object allocations via new. It is a + * light wrapper around std::auto_ptr and has the same semantics + * except that the copy constructor and assignment operator are deep + * copies (that is, they use T's copy constructor) rather than + * transferring ownership. + * + * This is useful for cases where you have a class which has a member + * variable that's dynamically allocated and you want to provide a + * valid copy constructor / assignment operator. With raw pointers or + * std::auto_ptr's, you'll have to write the copy constructor / + * assignment operator for this class - this is tedious and + * error-prone since you need to include all the members in the class. + * Using ScopedCopyablePtr's instead, the compiler-generated copy + * constructor and assignment operator for your class will be correct + * (if all the other member variables are POD or have correct + * copy constructors / assignment operators). + */ +template +class ScopedCopyablePtr +{ +public: + explicit ScopedCopyablePtr(T* ptr = NULL) + : mPtr(ptr) + { + } + + ScopedCopyablePtr(const ScopedCopyablePtr& rhs) + { + if (rhs.mPtr.get()) + { + mPtr.reset(new T(*rhs.mPtr)); + } + } + + const ScopedCopyablePtr& + operator=(const ScopedCopyablePtr& rhs) + { + if (this != &rhs) + { + if (rhs.mPtr.get()) + { + mPtr.reset(new T(*rhs.mPtr)); + } + else + { + mPtr.reset(); + } + } + + return *this; + } + + T* get() const + { + return mPtr.get(); + } + + T& operator*() const + { + return *mPtr; + } + + T* operator->() const + { + return mPtr.get(); + } + + void reset(T* ptr = NULL) + { + mPtr.reset(ptr); + } + +private: + std::auto_ptr mPtr; +}; +} + +#endif diff --git a/modules/c++/mem/include/mem/SharedPtr.h b/modules/c++/mem/include/mem/SharedPtr.h new file mode 100644 index 000000000..c66ce81d4 --- /dev/null +++ b/modules/c++/mem/include/mem/SharedPtr.h @@ -0,0 +1,156 @@ +/* ========================================================================= + * This file is part of mem-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * mem-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __MEM_SHARED_PTR_H__ +#define __MEM_SHARED_PTR_H__ + +#include +#include + +#include + +namespace mem +{ +/*! + * \class SharedPtr + * \brief This class provides RAII for object allocations via new. + * Additionally, it uses thread-safe reference counting so that the + * underlying pointer can be shared among multiple objects. When the + * last SharedPtr goes out of scope, the underlying pointer is + * deleted. + */ +template +class SharedPtr +{ +public: + explicit SharedPtr(T* ptr = NULL) : + mPtr(ptr) + { + // Initially we have a reference count of 1 + // In the constructor, we take ownership of the pointer no matter + // what, so temporarily wrap it in an auto_ptr in case creating the + // atomic counter throws + std::auto_ptr scopedPtr(ptr); + mRefCtr = new sys::AtomicCounter(1); + scopedPtr.release(); + } + + explicit SharedPtr(std::auto_ptr ptr) : + mPtr(ptr.get()) + { + // Initially we have a reference count of 1 + // If this throws, the auto_ptr will clean up the input pointer + // for us + mRefCtr = new sys::AtomicCounter(1); + + // We now own the pointer + ptr.release(); + } + + ~SharedPtr() + { + if (mRefCtr->decrementThenGet() == 0) + { + delete mRefCtr; + delete mPtr; + } + } + + SharedPtr(const SharedPtr& rhs) : + mRefCtr(rhs.mRefCtr), + mPtr(rhs.mPtr) + { + mRefCtr->increment(); + } + + const SharedPtr& + operator=(const SharedPtr& rhs) + { + if (this != &rhs) + { + if (mRefCtr->decrementThenGet() == 0) + { + // We were holding the last copy of this data prior to this + // assignment - need to clean it up + delete mRefCtr; + delete mPtr; + } + + mRefCtr = rhs.mRefCtr; + mPtr = rhs.mPtr; + mRefCtr->increment(); + } + + return *this; + } + + T* get() const + { + return mPtr; + } + + T& operator*() const + { + return *mPtr; + } + + T* operator->() const + { + return mPtr; + } + + sys::AtomicCounter::ValueType getCount() const + { + return mRefCtr->get(); + } + + void reset(T* ptr = NULL) + { + // We take ownership of the pointer no matter what, so temporarily + // wrap it in an auto_ptr in case creating the atomic counter throws. + // NOTE: We need to create newRefCtr on the side before decrementing + // mRefCtr. This way, we can provide the strong exception + // guarantee (i.e. the operation either succeeds or throws - the + // underlying object is always in a good state). + std::auto_ptr scopedPtr(ptr); + sys::AtomicCounter* const newRefCtr = new sys::AtomicCounter(1); + scopedPtr.release(); + + if (mRefCtr->decrementThenGet() == 0) + { + // We were holding the last copy of this data prior to this + // reset - need to clean up + delete mRefCtr; + delete mPtr; + } + + mRefCtr = newRefCtr; + mPtr = ptr; + } + +private: + sys::AtomicCounter* mRefCtr; + T* mPtr; +}; +} + +#endif diff --git a/modules/c++/mem/include/mem/VectorOfPointers.h b/modules/c++/mem/include/mem/VectorOfPointers.h new file mode 100644 index 000000000..95895c3d1 --- /dev/null +++ b/modules/c++/mem/include/mem/VectorOfPointers.h @@ -0,0 +1,189 @@ +/* ========================================================================= + * This file is part of mem-c++ + * ========================================================================= + * + * (C) Copyright 2013, General Dynamics - Advanced Information Systems + * + * mem-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __MEM_VECTOR_OF_POINTERS_H__ +#define __MEM_VECTOR_OF_POINTERS_H__ + +#include +#include +#include + +#include + +namespace mem +{ +/*! + * \class VectorOfPointers + * \brief This class provides safe cleanup for vectors of pointers + */ +template +class VectorOfPointers +{ +public: + VectorOfPointers() + { + } + + ~VectorOfPointers() + { + clear(); + } + + void clear() + { + for (size_t ii = 0; ii < mValues.size(); ++ii) + { + delete mValues[ii]; + } + mValues.clear(); + } + + const std::vector& get() const + { + return mValues; + } + + size_t size() const + { + return mValues.size(); + } + + bool empty() const + { + return mValues.empty(); + } + + T* operator[](std::ptrdiff_t idx) const + { + return mValues[idx]; + } + + T* back() const + { + return mValues.back(); + } + + void push_back(T* value) + { + std::auto_ptr scopedValue(value); + push_back(scopedValue); + } + + template + void push_back(OtherT* value) + { + std::auto_ptr scopedValue(value); + push_back(scopedValue); + } + + void push_back(std::auto_ptr value) + { + mValues.resize(mValues.size() + 1); + mValues.back() = value.release(); + } + + template + void push_back(std::auto_ptr value) + { + mValues.resize(mValues.size() + 1); + mValues.back() = value.release(); + } + +private: + // Noncopyable + VectorOfPointers(const VectorOfPointers& ); + const VectorOfPointers& operator=(const VectorOfPointers& ); + +private: + std::vector mValues; +}; + +template + class VectorOfSharedPointers +{ +public: + VectorOfSharedPointers() + { + } + + void clear() + { + mValues.clear(); + } + + std::vector get() const + { + std::vector values(mValues.size()); + for (size_t ii = 0; ii < mValues.size(); ++ii) + { + values[ii] = mValues[ii].get(); + } + return values; + } + + size_t size() const + { + return mValues.size(); + } + + bool empty() const + { + return mValues.empty(); + } + + mem::SharedPtr operator[](std::ptrdiff_t idx) const + { + return mValues[idx]; + } + + void push_back(T* value) + { + std::auto_ptr scopedValue(value); + push_back(scopedValue); + } + + template + void push_back(OtherT* value) + { + std::auto_ptr scopedValue(value); + push_back(scopedValue); + } + + void push_back(std::auto_ptr value) + { + mValues.resize(mValues.size() + 1); + mValues.back().reset(value.release()); + } + + template + void push_back(std::auto_ptr value) + { + mValues.resize(mValues.size() + 1); + mValues.back().reset(value.release()); + } + +private: + std::vector > mValues; +}; +} + +#endif diff --git a/modules/c++/mem/unittests/test_scoped_copyable_ptr.cpp b/modules/c++/mem/unittests/test_scoped_copyable_ptr.cpp new file mode 100644 index 000000000..7ba793c96 --- /dev/null +++ b/modules/c++/mem/unittests/test_scoped_copyable_ptr.cpp @@ -0,0 +1,154 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include + +#include "TestCase.h" + +namespace +{ +struct Foo +{ + Foo() + : val1(0), + val2(0) + { + } + + size_t val1; + size_t val2; +}; + +struct Bar +{ + Bar() + : val3(0) + { + } + + mem::ScopedCopyablePtr foo; + size_t val3; +}; + +class AssignOnDestruct +{ +public: + AssignOnDestruct(size_t &ref, size_t finalVal) : + mRef(ref), + mFinalVal(finalVal) + { + } + + ~AssignOnDestruct() + { + mRef = mFinalVal; + } + +private: + size_t& mRef; + const size_t mFinalVal; +}; + +TEST_CASE(testCopyConstructor) +{ + // Initialize the values + Bar bar1; + bar1.foo.reset(new Foo()); + bar1.foo->val1 = 10; + bar1.foo->val2 = 20; + bar1.val3 = 30; + + // Show that the compiler-generated copy constructor is correct + Bar bar2(bar1); + TEST_ASSERT_EQ(bar2.foo->val1, 10); + TEST_ASSERT_EQ(bar2.foo->val2, 20); + TEST_ASSERT_EQ(bar2.val3, 30); + + // Show it was a deep copy + bar2.foo->val1 = 40; + bar2.foo->val2 = 50; + bar2.val3 = 60; + TEST_ASSERT_EQ(bar1.foo->val1, 10); + TEST_ASSERT_EQ(bar1.foo->val2, 20); + TEST_ASSERT_EQ(bar1.val3, 30); +} + +TEST_CASE(testAssignmentOperator) +{ + // Initialize the values + Bar bar1; + bar1.foo.reset(new Foo()); + bar1.foo->val1 = 10; + bar1.foo->val2 = 20; + bar1.val3 = 30; + + // Show that the compiler-generated assignment operator is correct + Bar bar2; + bar2 = bar1; + TEST_ASSERT_EQ(bar2.foo->val1, 10); + TEST_ASSERT_EQ(bar2.foo->val2, 20); + TEST_ASSERT_EQ(bar2.val3, 30); + + // Show it was a deep copy + bar2.foo->val1 = 40; + bar2.foo->val2 = 50; + bar2.val3 = 60; + TEST_ASSERT_EQ(bar1.foo->val1, 10); + TEST_ASSERT_EQ(bar1.foo->val2, 20); + TEST_ASSERT_EQ(bar1.val3, 30); +} + +TEST_CASE(testDestructor) +{ + // When the ScopedCopyablePtr goes out of scope, it should delete the + // pointer which will cause the AssignOnDestruct destructor to assign + // 'val' + size_t val(0); + { + const mem::ScopedCopyablePtr ptr( + new AssignOnDestruct(val, 334)); + TEST_ASSERT_EQ(val, 0); + } + + TEST_ASSERT_EQ(val, 334); +} + +TEST_CASE(testSyntax) +{ + Foo* const rawPtr(new Foo()); + const mem::ScopedCopyablePtr ptr(rawPtr); + + TEST_ASSERT_EQ(ptr.get(), rawPtr); + TEST_ASSERT_EQ(&*ptr, rawPtr); + TEST_ASSERT_EQ(&(ptr->val1), &(rawPtr->val1)); +} +} + +int main(int argc, char** argv) +{ + TEST_CHECK(testCopyConstructor); + TEST_CHECK(testAssignmentOperator); + TEST_CHECK(testDestructor); + TEST_CHECK(testSyntax); + + return 0; +} diff --git a/modules/c++/mem/unittests/test_shared_ptr.cpp b/modules/c++/mem/unittests/test_shared_ptr.cpp new file mode 100644 index 000000000..b1945bae0 --- /dev/null +++ b/modules/c++/mem/unittests/test_shared_ptr.cpp @@ -0,0 +1,168 @@ +/* ========================================================================= + * This file is part of mem-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * mem-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include + +#include "TestCase.h" + +namespace +{ +TEST_CASE(testNullCopying) +{ + mem::SharedPtr ptr1; + TEST_ASSERT_EQ(ptr1.get(), static_cast(NULL)); + + // Copy construction + const mem::SharedPtr ptr2(ptr1); + TEST_ASSERT_EQ(ptr2.get(), static_cast(NULL)); + + // Assignment operator + mem::SharedPtr ptr3; + ptr3 = ptr1; + TEST_ASSERT_EQ(ptr3.get(), static_cast(NULL)); + + ptr1.reset(); + TEST_ASSERT_EQ(ptr1.get(), static_cast(NULL)); +} + +TEST_CASE(testAutoPtrConstructor) +{ + int * const rawPtr(new int(89)); + std::auto_ptr autoPtr(rawPtr); + const mem::SharedPtr ptr(autoPtr); + TEST_ASSERT_EQ(ptr.get(), rawPtr); + TEST_ASSERT_EQ(autoPtr.get(), static_cast(NULL)); + TEST_ASSERT_EQ(ptr.getCount(), 1); +} + +TEST_CASE(testCopying) +{ + int * const rawPtr(new int(89)); + std::auto_ptr > ptr3; + { + mem::SharedPtr ptr1(rawPtr); + TEST_ASSERT_EQ(ptr1.get(), rawPtr); + TEST_ASSERT_EQ(*ptr1.get(), 89); + TEST_ASSERT_EQ(ptr1.getCount(), 1); + + const mem::SharedPtr ptr2(ptr1); + TEST_ASSERT_EQ(ptr1.get(), rawPtr); + TEST_ASSERT_EQ(ptr2.get(), rawPtr); + TEST_ASSERT_EQ(*ptr2.get(), 89); + TEST_ASSERT_EQ(ptr1.getCount(), 2); + TEST_ASSERT_EQ(ptr2.getCount(), 2); + + // We already know they're pointing at the same underlying data, but + // show it this way too for kicks + *ptr2.get() = 334; + TEST_ASSERT_EQ(*ptr1.get(), 334); + TEST_ASSERT_EQ(*ptr2.get(), 334); + + // Decrement the reference count + ptr1.reset(); + TEST_ASSERT_EQ(*ptr2.get(), 334); + TEST_ASSERT_EQ(ptr2.getCount(), 1); + + // Do the same thing but show that ptr2 going out of scope is + // equivalent to it being reset + ptr3.reset(new mem::SharedPtr(ptr2)); + TEST_ASSERT_EQ(ptr3->get(), rawPtr); + TEST_ASSERT_EQ(ptr2.getCount(), 2); + TEST_ASSERT_EQ(ptr3->getCount(), 2); + } + + TEST_ASSERT_EQ(ptr3->get(), rawPtr); + TEST_ASSERT_EQ(ptr3->getCount(), 1); +} + +TEST_CASE(testAssigning) +{ + int * const rawPtr(new int(89)); + mem::SharedPtr ptr3; + { + mem::SharedPtr ptr1(rawPtr); + TEST_ASSERT_EQ(ptr1.get(), rawPtr); + TEST_ASSERT_EQ(*ptr1.get(), 89); + TEST_ASSERT_EQ(ptr1.getCount(), 1); + + mem::SharedPtr ptr2; + ptr2 = ptr1; + TEST_ASSERT_EQ(ptr1.get(), rawPtr); + TEST_ASSERT_EQ(ptr2.get(), rawPtr); + TEST_ASSERT_EQ(*ptr2.get(), 89); + TEST_ASSERT_EQ(ptr1.getCount(), 2); + TEST_ASSERT_EQ(ptr2.getCount(), 2); + + // We already know they're pointing at the same underlying data, but + // show it this way too for kicks + *ptr2.get() = 334; + TEST_ASSERT_EQ(*ptr1.get(), 334); + TEST_ASSERT_EQ(*ptr2.get(), 334); + + // Decrement the reference count + ptr1.reset(); + TEST_ASSERT_EQ(*ptr2.get(), 334); + TEST_ASSERT_EQ(ptr2.getCount(), 1); + + // Do the same thing but show that ptr2 going out of scope is + // equivalent to it being reset + ptr3 = ptr2; + TEST_ASSERT_EQ(ptr3.get(), rawPtr); + TEST_ASSERT_EQ(ptr2.getCount(), 2); + TEST_ASSERT_EQ(ptr3.getCount(), 2); + } + + TEST_ASSERT_EQ(ptr3.get(), rawPtr); + TEST_ASSERT_EQ(ptr3.getCount(), 1); +} + +struct Foo +{ + Foo(size_t val) : + mVal(val) + { + } + + size_t mVal; +}; + +TEST_CASE(testSyntax) +{ + Foo* const rawPtr(new Foo(123)); + const mem::SharedPtr ptr(rawPtr); + + TEST_ASSERT_EQ(ptr.get(), rawPtr); + TEST_ASSERT_EQ(&*ptr, rawPtr); + TEST_ASSERT_EQ(&(ptr->mVal), &(rawPtr->mVal)); +} +} + +int main(int argc, char **argv) +{ + TEST_CHECK(testNullCopying); + TEST_CHECK(testAutoPtrConstructor); + TEST_CHECK(testCopying); + TEST_CHECK(testAssigning); + TEST_CHECK(testSyntax); + + return 0; +} diff --git a/modules/c++/mem/wscript b/modules/c++/mem/wscript new file mode 100644 index 000000000..044809aa4 --- /dev/null +++ b/modules/c++/mem/wscript @@ -0,0 +1,9 @@ +NAME = 'mem' +MAINTAINER = 'asylvest@users.sourceforge.net' +VERSION = '1.0' +MODULE_DEPS = 'sys' + +options = configure = distclean = lambda p: None + +def build(bld): + bld.module(**globals()) diff --git a/modules/c++/mt/README.txt b/modules/c++/mt/README.txt new file mode 100644 index 000000000..7f5590ee4 --- /dev/null +++ b/modules/c++/mt/README.txt @@ -0,0 +1,4 @@ +Under linux, I have had to explicitly link with -lpthread. +If you get ThreadPosix linker errors, try sticking -lpthread at the +end of your list of libraries + diff --git a/modules/c++/mt/include/import/mt.h b/modules/c++/mt/include/import/mt.h new file mode 100644 index 000000000..c9186a853 --- /dev/null +++ b/modules/c++/mt/include/import/mt.h @@ -0,0 +1,47 @@ +/* ========================================================================= + * This file is part of mt-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * mt-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __IMPORT_MT_H__ +#define __IMPORT_MT_H__ + +#include "mt/RequestQueue.h" +#include "mt/ThreadPoolException.h" +#include "mt/BasicThreadPool.h" +#include "mt/GenericRequestHandler.h" +#include "mt/Singleton.h" +#include "mt/CriticalSection.h" +#include "mt/AbstractThreadPool.h" +#include "mt/WorkerThread.h" +#include "mt/AbstractTiedThreadPool.h" +#include "mt/TiedWorkerThread.h" +#include "mt/GenerationThreadPool.h" +#include "mt/ThreadGroup.h" +#include "mt/ThreadPlanner.h" +#include "mt/Runnable1D.h" + +#include "mt/CPUAffinityInitializer.h" +#include "mt/CPUAffinityThreadInitializer.h" +#include "mt/LinuxCPUAffinityInitializer.h" +#include "mt/LinuxCPUAffinityThreadInitializer.h" + +#endif diff --git a/modules/c++/mt/include/mt/AbstractThreadPool.h b/modules/c++/mt/include/mt/AbstractThreadPool.h new file mode 100644 index 000000000..36352bd12 --- /dev/null +++ b/modules/c++/mt/include/mt/AbstractThreadPool.h @@ -0,0 +1,140 @@ +/* ========================================================================= + * This file is part of mt-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * mt-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __MT_ABSTRACT_THREAD_POOL_H__ +#define __MT_ABSTRACT_THREAD_POOL_H__ + +#include + +#include "sys/Thread.h" +#include "mt/RequestQueue.h" +#include "mt/ThreadPoolException.h" +#include "mt/WorkerThread.h" +#include "mem/SharedPtr.h" + +namespace mt +{ +/*! + * \class AbstractThreadPool + * \brief Partially implemented thread pool with a consumer-producer queue + * + * This class is a partial implementation of a thread pool. + * The production of threads has been left up to the derived class. + * Additionally the request to be performed/read is not specialized. + * The derived class would presumably also specialize this type + * in order to clarify the derived type of WorkerThread's + * performTask() behavior. + * + */ +template class AbstractThreadPool +{ +public: + + /*! + * Constructor. Set up the thread pool. + * \param numThreads the number of threads + */ + AbstractThreadPool(size_t numThreads = 0) : + mNumThreads(numThreads) + {} + + + //! Destructor + virtual ~AbstractThreadPool() + { + join();//destroy(); + } + + /*! + * Intialize and start each thread running. + * Typically the caller will either join at this point + * or begin another simultaneously running loop task. + * + */ + void start() + { + for (size_t i = 0; i < mNumThreads; i++) + { + mPool.push_back(mem::SharedPtr(newWorker())); + mPool[i]->start(); + } + } + + /*! + * This function cannot be implemented until the WorkerThread + * is overriden with a performTask() function. At that point, this + * function can be derived to produce a pointer to the base class, + * pointing at the newly derived worker thread. + */ + virtual WorkerThread* newWorker() = 0; + + /*! + * Wait on all the threads in a pool. If the WorkerThread's run() + * behavior is not overriden, this will lock up the thread of control + * until the program is shut down. + * + */ + void join() + { + for (size_t i = 0; i < mPool.size(); i++) + { + dbg_printf("mPool[%d]->join()\n", i); + mPool[i]->join(); + + } + destroy(); + } + + void setNumThreads(size_t numThreads) + { + mNumThreads = numThreads; + } + + void addRequest(Request_T &handler) + { + mRequestQueue.enqueue(handler); + } + + /*! + * Get the number of threads in the pool + * \return The number of threads in the pool + */ + size_t getNumThreads() const + { + return mPool.size(); + } + +protected: + + void destroy() + { + mPool.clear(); + } + + size_t mNumThreads; + std::vector > mPool; + mt::RequestQueue mRequestQueue; +}; +} + +#endif diff --git a/modules/c++/mt/include/mt/AbstractTiedThreadPool.h b/modules/c++/mt/include/mt/AbstractTiedThreadPool.h new file mode 100644 index 000000000..a7cb80351 --- /dev/null +++ b/modules/c++/mt/include/mt/AbstractTiedThreadPool.h @@ -0,0 +1,75 @@ +/* ========================================================================= + * This file is part of mt-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * mt-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __MT_ABSTRACT_TIED_THREAD_POOL_H__ +#define __MT_ABSTRACT_TIED_THREAD_POOL_H__ + +#include "mt/AbstractThreadPool.h" +#include "mt/TiedWorkerThread.h" +#include "mt/CPUAffinityInitializer.h" + +namespace mt +{ +template +class AbstractTiedThreadPool : public AbstractThreadPool +{ + +public: + AbstractTiedThreadPool(unsigned short numThreads = 0) : AbstractThreadPool(numThreads) {} + + virtual ~AbstractTiedThreadPool(){} + + virtual void initialize(CPUAffinityInitializer* affinityInit = NULL) + { + mAffinityInit = affinityInit; + } + virtual CPUAffinityThreadInitializer* getCPUAffinityThreadInitializer() + { + CPUAffinityThreadInitializer* threadInit = NULL; + + // If we were passed a schematic + // for initializing thread affinity... + if (mAffinityInit) + { + threadInit = mAffinityInit->newThreadInitializer(); + } + return threadInit; + } + + virtual mt::WorkerThread* newWorker() + { + return newTiedWorker(&this->mRequestQueue, + getCPUAffinityThreadInitializer()); + } + + protected: + virtual mt::TiedWorkerThread* newTiedWorker(mt::RequestQueue* q, + CPUAffinityThreadInitializer* init) = 0; + +private: + CPUAffinityInitializer* mAffinityInit; +}; + +} +#endif + diff --git a/modules/c++/mt/include/mt/BasicThreadPool.h b/modules/c++/mt/include/mt/BasicThreadPool.h new file mode 100644 index 000000000..21f1c3b0a --- /dev/null +++ b/modules/c++/mt/include/mt/BasicThreadPool.h @@ -0,0 +1,141 @@ +/* ========================================================================= + * This file is part of mt-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * mt-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __MT_BASIC_THREAD_POOL_H__ +#define __MT_BASIC_THREAD_POOL_H__ + +#include +#include "except/Exception.h" +#include "sys/Mutex.h" +#include "sys/Thread.h" +#include "mt/RequestQueue.h" +#include "mt/GenericRequestHandler.h" +#include "mt/ThreadPoolException.h" +#include "mem/SharedPtr.h" + +namespace mt +{ +template +class BasicThreadPool +{ +public: + + /*! Constructor. Set up the thread pool. + * \param numThreads the number of threads + */ + BasicThreadPool(size_t numThreads = 0) : + mStarted(false) + { + mNumThreads = numThreads; + } + + //! Deconstructor + virtual ~BasicThreadPool() + { + //destroy(static_cast(mPool.size())); + shutdown(); + } + + void start() + { + if (mStarted) + throw(ThreadPoolException("The thread pool is already started.")); + + mStarted = true; + + for (size_t i = 0; i < mNumThreads; i++) + { + mPool.push_back(mem::SharedPtr(new sys::Thread(newRequestHandler()))); + mPool[i]->start(); + } + } + + void join() + { + for (size_t i = 0; i < mPool.size(); i++) + { + dbg_printf("mPool[%d]->join()\n", i); + mPool[i]->join(); + } + destroy(); + mStarted = false; + } + + void grow(size_t bySize) + { + mNumThreads += bySize; + } + + void shrink(size_t bySize) + { + if (mStarted) + join(); + + mNumThreads = (bySize > mNumThreads) ? 0 : mNumThreads - bySize; + } + + void addRequest(sys::Runnable *handler) + { + mHandlerQueue.enqueue(handler); + } + + size_t getSize() const + { + return mPool.size(); + } + + void shutdown() + { + // Add requests that signal the thread should stop + static sys::Runnable *stopSignal = NULL; + for (size_t i = 0; i < mPool.size(); ++i) + { + addRequest(stopSignal); + } + // Join all threads + join(); + // Clear the request queue - mainly just cleanup in case we reuse + mHandlerQueue.clear(); + } + +protected: + + // Derive this to use a new kind of request handler + // For instance, you may want an IterativeRequestHandler + virtual RequestHandler_T *newRequestHandler() + { + return new RequestHandler_T(&mHandlerQueue); + } + + void destroy() + { + mPool.clear(); + } + + bool mStarted; + size_t mNumThreads; + std::vector > mPool; + mt::RunnableRequestQueue mHandlerQueue; +}; +} + +#endif diff --git a/modules/c++/mt/include/mt/CPUAffinityInitializer.h b/modules/c++/mt/include/mt/CPUAffinityInitializer.h new file mode 100644 index 000000000..ea0991b65 --- /dev/null +++ b/modules/c++/mt/include/mt/CPUAffinityInitializer.h @@ -0,0 +1,40 @@ +/* ========================================================================= + * This file is part of mt-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * mt-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __MT_CPU_AFFINITY_INITIALIZER_H__ +#define __MT_CPU_AFFINITY_INITIALIZER_H__ + +#include "mt/CPUAffinityThreadInitializer.h" + +namespace mt +{ + class CPUAffinityInitializer + { + public: + CPUAffinityInitializer() {} + virtual ~CPUAffinityInitializer() {} + virtual CPUAffinityThreadInitializer* newThreadInitializer() = 0; + }; +} + +#endif diff --git a/modules/c++/mt/include/mt/CPUAffinityThreadInitializer.h b/modules/c++/mt/include/mt/CPUAffinityThreadInitializer.h new file mode 100644 index 000000000..0643b8aa8 --- /dev/null +++ b/modules/c++/mt/include/mt/CPUAffinityThreadInitializer.h @@ -0,0 +1,37 @@ +/* ========================================================================= + * This file is part of mt-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * mt-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __MT_CPU_AFFINITY_THREAD_INITIALIZER_H__ +#define __MT_CPU_AFFINITY_THREAD_INITIALIZER_H__ + +namespace mt +{ + class CPUAffinityThreadInitializer + { + public: + CPUAffinityThreadInitializer() {} + virtual ~CPUAffinityThreadInitializer() {} + virtual void initialize() = 0; + }; +} +#endif diff --git a/modules/c++/mt/include/mt/CriticalSection.h b/modules/c++/mt/include/mt/CriticalSection.h new file mode 100644 index 000000000..9dd02b8dc --- /dev/null +++ b/modules/c++/mt/include/mt/CriticalSection.h @@ -0,0 +1,106 @@ +/* ========================================================================= + * This file is part of mt-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * mt-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __MT_CRITICAL_SECTION_H__ +#define __MT_CRITICAL_SECTION_H__ + +/*! + * \file + * \brief Scope-based critical sections + * + * This object locks when it is created and unlocks + * as soon as it goes out of scope. This should be used + * You should never new allocate this object, lest you + * should forget to delete it. You should also never modify the state of + * the mutex it owns while this object exists. + * + */ +namespace mt +{ +/*! + * \class CriticalSection + * \brief Scope-based critical section object + * This object locks when it is created and unlocks + * as soon as it goes out of scope. + * + * \code + * void performCSOp(Info& specialInfo) + * { + * CriticalSection cs(&globalLock); // We now have the lock + * GlobalBuffer.remove(specialInfo); + * } + * \endcode + */ +template class CriticalSection +{ +public: + //! Constructor. Lock the mutex. + CriticalSection(T* mutex) : + mMutex(mutex), + mIsLocked(false) + { + manualLock(); + } + + //! Destructor. Unlock the mutex (if necessary). + ~CriticalSection() + { + if (mIsLocked) + { + try + { + manualUnlock(); + } + catch (...) + { + // Don't throw out of the destructor. + } + } + } + + //! Manual unlock the CS. You probably don't want to use this. + void manualUnlock() + { + mMutex->unlock(); + mIsLocked = false; + } + + //! Manual lock the CS. You probably don't want to use this. + void manualLock() + { + mMutex->lock(); + mIsLocked = true; + } + +private: + // Noncopyable + CriticalSection(const CriticalSection& ); + const CriticalSection& operator=(const CriticalSection& ); + +private: + T* const mMutex; + bool mIsLocked; + +}; +} +#endif diff --git a/modules/c++/mt/include/mt/GenerationThreadPool.h b/modules/c++/mt/include/mt/GenerationThreadPool.h new file mode 100644 index 000000000..ea4087cd0 --- /dev/null +++ b/modules/c++/mt/include/mt/GenerationThreadPool.h @@ -0,0 +1,104 @@ +/* ========================================================================= + * This file is part of mt-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * mt-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __MT_GENERATION_THREAD_POOL_H__ +#define __MT_GENERATION_THREAD_POOL_H__ + +#if !defined(__APPLE_CC__) + +#include +#include "mt/BasicThreadPool.h" +#include "mt/CPUAffinityInitializer.h" +#include "mt/CPUAffinityThreadInitializer.h" + +namespace mt +{ + class TiedRequestHandler : public sys::Runnable + { + RunnableRequestQueue* mRequestQueue; + sys::Semaphore* mSem; + CPUAffinityThreadInitializer* mAffinityInit; + + public: + TiedRequestHandler(RunnableRequestQueue* requestQueue) : + mRequestQueue(requestQueue), mAffinityInit(NULL) {} + + virtual ~TiedRequestHandler(); + + virtual void setSemaphore(sys::Semaphore* sem) + { + mSem = sem; + } + virtual void setAffinityInit(CPUAffinityThreadInitializer* affinityInit) + { + mAffinityInit = affinityInit; + } + + // If we have a thread initializer, tie down our handler to a CPU + virtual void initialize(); + + virtual void run(); + }; + + class GenerationThreadPool : public BasicThreadPool + { + sys::Semaphore mGenerationSync; + CPUAffinityInitializer* mAffinityInit; + int mGenSize; + public: + GenerationThreadPool(unsigned short numThreads = 0, + CPUAffinityInitializer* affinityInit = NULL) + : BasicThreadPool(numThreads), + mAffinityInit(affinityInit), mGenSize(0) + { + } + virtual ~GenerationThreadPool() {} + + virtual TiedRequestHandler *newRequestHandler() + { + TiedRequestHandler* handler = BasicThreadPool::newRequestHandler(); + handler->setSemaphore(&mGenerationSync); + + if (mAffinityInit) + handler->setAffinityInit(mAffinityInit->newThreadInitializer()); + + + return handler; + } + + // Not set up for multiple producers + void addGroup(std::vector& toRun); + + // Not set up for multiple producers + void waitGroup(); + + void addAndWaitGroup(std::vector& toRun) + { + addGroup(toRun); + waitGroup(); + } + + }; +} +#endif +#endif diff --git a/modules/c++/mt/include/mt/GenericRequestHandler.h b/modules/c++/mt/include/mt/GenericRequestHandler.h new file mode 100644 index 000000000..2ab19aa08 --- /dev/null +++ b/modules/c++/mt/include/mt/GenericRequestHandler.h @@ -0,0 +1,66 @@ +/* ========================================================================= + * This file is part of mt-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * mt-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __MT_GENERIC_REQUEST_HANDLER_H__ +#define __MT_GENERIC_REQUEST_HANDLER_H__ + +#include "sys/Thread.h" +#include "mt/RequestQueue.h" + +namespace mt +{ + +/*! + * \class GenericRequestHandler + * \brief Request handler for BasicThreadPool + * + * This class pulls a runnable off the BasicThreadPool + * request queue and runs it, in a loop that never terminates. + * + * This class is really only used if you are using a BasicThreadPool. + * + */ +class GenericRequestHandler : public sys::Runnable +{ +public: + //! Constructor + GenericRequestHandler(RunnableRequestQueue* request) : + mRequest(request) + {} + + //! Deconstructor + ~GenericRequestHandler() + {} + + /*! + * Dequeue and run requests in a non-terminating loop + */ + virtual void run(); + +protected: + RunnableRequestQueue *mRequest; +}; +} + + +#endif diff --git a/modules/c++/mt/include/mt/LinuxCPUAffinityInitializer.h b/modules/c++/mt/include/mt/LinuxCPUAffinityInitializer.h new file mode 100644 index 000000000..1f3f5934b --- /dev/null +++ b/modules/c++/mt/include/mt/LinuxCPUAffinityInitializer.h @@ -0,0 +1,57 @@ +/* ========================================================================= + * This file is part of mt-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * mt-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __MT_LINUX_CPU_AFFINITY_INITIALIZER_H__ +#define __MT_LINUX_CPU_AFFINITY_INITIALIZER_H__ + +#if !defined(__APPLE_CC__) +#if defined(__linux) || defined(__linux__) + + +#include "mt/CPUAffinityInitializer.h" +#include "mt/LinuxCPUAffinityThreadInitializer.h" + +namespace mt +{ + class LinuxCPUAffinityInitializer : public mt::CPUAffinityInitializer + { + int mNextCPU; + cpu_set_t nextCPU(); + public: + LinuxCPUAffinityInitializer(int initialOffset) : + mNextCPU(initialOffset) {} + + ~LinuxCPUAffinityInitializer() {} + + LinuxCPUAffinityThreadInitializer* newThreadInitializer() + { + return new LinuxCPUAffinityThreadInitializer(nextCPU()); + } + + }; +} + +#endif +#endif +#endif + diff --git a/modules/c++/mt/include/mt/LinuxCPUAffinityThreadInitializer.h b/modules/c++/mt/include/mt/LinuxCPUAffinityThreadInitializer.h new file mode 100644 index 000000000..59272ffb8 --- /dev/null +++ b/modules/c++/mt/include/mt/LinuxCPUAffinityThreadInitializer.h @@ -0,0 +1,53 @@ +/* ========================================================================= + * This file is part of mt-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * mt-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __MT_LINUX_CPU_AFFINITY_THREAD_INITIALIZER_H__ +#define __MT_LINUX_CPU_AFFINITY_THREAD_INITIALIZER_H__ + +#if !defined(__APPLE_CC__) +#if defined(__linux) || defined(__linux__) + +#include +#include +#include +#include +#define gettid() syscall(SYS_gettid) + +#include +#include "mt/CPUAffinityThreadInitializer.h" + +namespace mt +{ + class LinuxCPUAffinityThreadInitializer : public mt::CPUAffinityThreadInitializer + { + cpu_set_t mCPU; + public: + LinuxCPUAffinityThreadInitializer(const cpu_set_t& cpu); + void initialize(); + }; +} + + +#endif +#endif +#endif diff --git a/modules/c++/mt/include/mt/RequestQueue.h b/modules/c++/mt/include/mt/RequestQueue.h new file mode 100644 index 000000000..b16582191 --- /dev/null +++ b/modules/c++/mt/include/mt/RequestQueue.h @@ -0,0 +1,150 @@ +/* ========================================================================= + * This file is part of mt-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * mt-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __MT_REQUEST_QUEUE_H__ +#define __MT_REQUEST_QUEUE_H__ + +#include +#include "sys/Thread.h" +#include "sys/ConditionVar.h" +#include "sys/Mutex.h" +#include "sys/Dbg.h" + +namespace mt +{ + +/*! + * + * \class RequestQueue + * \brief Locked, dual condition request queue + * + * This is a generic class for locked buffers. Stick + * anything in T and it will be protected by a queue lock + * and two condition variables. When you call dequeue, this + * class blocks until there is data (there is a critical section). + * + * This class is the basis for the two provided thread pool APIs, + * AbstractThreadPool and BasicThreadPool + * + * + */ + +template +class RequestQueue +{ +public: + + //! Default constructor + RequestQueue() : + mAvailableSpace(&mQueueLock), + mAvailableItems(&mQueueLock) + { + } + + // Put a (copy of, unless T is a pointer) request on the queue + void enqueue(T request) + { +#ifdef THREAD_DEBUG + dbg_printf("Locking (enqueue)\n"); +#endif + mQueueLock.lock(); + mRequestQueue.push(request); +#ifdef THREAD_DEBUG + dbg_printf("Unlocking (enqueue), new size [%d]\n", mRequestQueue.size()); +#endif + mQueueLock.unlock(); + + mAvailableItems.signal(); + } + + // Retrieve (by reference) T from the queue. blocks until ok + void dequeue(T& request) + { +#ifdef THREAD_DEBUG + dbg_printf("Locking (dequeue)\n"); +#endif + mQueueLock.lock(); + while (isEmpty()) + { + mAvailableItems.wait(); + } + + request = mRequestQueue.front(); + mRequestQueue.pop(); + +#ifdef THREAD_DEBUG + dbg_printf("Unlocking (dequeue), new size [%d]\n", mRequestQueue.size()); +#endif + mQueueLock.unlock(); + mAvailableSpace.signal(); + } + + // Check to see if its empty + inline bool isEmpty() + { + return (mRequestQueue.size() == 0); + } + + // Check the length + inline int length() + { + return mRequestQueue.size(); + } + + void clear() + { +#ifdef THREAD_DEBUG + dbg_printf("Locking (dequeue)\n"); +#endif + mQueueLock.lock(); + while (!isEmpty()) + { + mRequestQueue.pop(); + } + +#ifdef THREAD_DEBUG + dbg_printf("Unlocking (dequeue), new size [%d]\n", mRequestQueue.size()); +#endif + mQueueLock.unlock(); + mAvailableSpace.signal(); + } + +private: + // Noncopyable + RequestQueue(const RequestQueue& ); + const RequestQueue& operator=(const RequestQueue& ); + +private: + //! The internal data structure + std::queue mRequestQueue; + //! The synchronizer + sys::Mutex mQueueLock; + //! This condition is "is there space?" + sys::ConditionVar mAvailableSpace; + //! This condition is "is there an item?" + sys::ConditionVar mAvailableItems; +}; + +typedef RequestQueue RunnableRequestQueue; +} + +#endif // __MT_REQUEST_QUEUE_H__ diff --git a/modules/c++/mt/include/mt/Runnable1D.h b/modules/c++/mt/include/mt/Runnable1D.h new file mode 100644 index 000000000..bb73e94bf --- /dev/null +++ b/modules/c++/mt/include/mt/Runnable1D.h @@ -0,0 +1,113 @@ +#ifndef __MT_RUNNABLE_1D_H__ +#define __MT_RUNNABLE_1D_H__ + +#include +#include + +#include +#include +#include +#include "mt/ThreadPlanner.h" +#include "mt/ThreadGroup.h" + +namespace mt +{ +template +class Runnable1D : public sys::Runnable +{ +public: + Runnable1D(size_t startElement, + size_t numElements, + const OpT& op) : + mStartElement(startElement), + mEndElement(startElement + numElements), + mOp(op) + { + } + + virtual void run() + { + for (size_t ii = mStartElement; ii < mEndElement; ++ii) + { + mOp(ii); + } + } + +private: + const size_t mStartElement; + const size_t mEndElement; + const OpT& mOp; +}; + +template +void run1D(size_t numElements, size_t numThreads, const OpT& op) +{ + if (numThreads <= 1) + { + Runnable1D(0, numElements, op).run(); + } + else + { + ThreadGroup threads; + const ThreadPlanner planner(numElements, numThreads); + + size_t threadNum(0); + size_t startElement(0); + size_t numElementsThisThread(0); + while(planner.getThreadInfo(threadNum++, startElement, numElementsThisThread)) + { + threads.createThread(new Runnable1D( + startElement, numElementsThisThread, op)); + } + threads.joinAll(); + } +} + +// Same as above but each thread gets their own 'op' +// This is useful when each thread needs its own local storage and/or you +// need access to a per-thread result afterwards (make these member variables +// mutable since operator() is const). +template +void run1D(size_t numElements, size_t numThreads, const std::vector& ops) +{ + if (ops.size() != numThreads) + { + std::ostringstream ostr; + ostr << "Got " << numThreads << " threads but " << ops.size() + << " functors"; + throw except::Exception(Ctxt(ostr.str())); + } + + if (numThreads <= 1) + { + Runnable1D(0, numElements, ops[0]).run(); + } + else + { + ThreadGroup threads; + const ThreadPlanner planner(numElements, numThreads); + + size_t threadNum(0); + size_t startElement(0); + size_t numElementsThisThread(0); + while(planner.getThreadInfo(threadNum, startElement, numElementsThisThread)) + { + threads.createThread(new Runnable1D( + startElement, numElementsThisThread, ops[threadNum++])); + } + threads.joinAll(); + } +} + +// Same as above but each thread gets their own copy-constructed copy of 'op' +// This is useful when each thread needs its own local storage (make this +// scratch space mutable since operator() is const). +template +void run1DWithCopies(size_t numElements, size_t numThreads, const OpT& op) +{ + const std::vector ops(numThreads, op); + run1D(numElements, numThreads, ops); +} +} + +#endif diff --git a/modules/c++/mt/include/mt/Singleton.h b/modules/c++/mt/include/mt/Singleton.h new file mode 100644 index 000000000..8f0d2f147 --- /dev/null +++ b/modules/c++/mt/include/mt/Singleton.h @@ -0,0 +1,168 @@ +/* ========================================================================= + * This file is part of mt-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * mt-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __MT_SINGLETON_H__ +#define __MT_SINGLETON_H__ + +#include +#include "mt/CriticalSection.h" + +namespace mt +{ + +/*! + * \brief Templated, thread-safe Singleton + * + * The Singleton class guarantees that at any given time in an application's + * life cycle, only 1 instance of the templated object will be in existence. + * Singleton is a great way to implement the Manager design pattern. + * + * The Singleton takes in the Object class type as the first template parameter. + * So, for example, if you had a Logger class and you wanted only one instance + * of it throughout your program, you could do this: + * + * typedef mt::Singleton LoggerManager; + * ... + * LoggerManager::getInstance().log("singleton log message"); + * + * The second template parameter is a bool which denotes whether the Singleton + * should automatically destroy the owned object at program exit. By default, + * this flag is set to false, thus NOT destroying the internal object at exit. + * The public destroy() method of the Singleton can be used to manually destroy + * the singleton object. This lets the user facilitate how/when the Singleton + * gets destroyed. + * + * Most users will want to set AutoDestroy to true, since they want the memory + * to be freed up automatically at exit. Be careful when keeping AutoDestroy + * set to false, for this means that you, the user, are in charge of calling + * destroy() when you are finished using the Singleton. Going back to the + * previous example of a singleton Logger, here is how you would create one + * that gets destroyed at program exit: + * + * typedef mt::Singleton LoggerManager; + * + * Notice that this implementation of the Singleton pattern uses the + * atexit method for deleting the singleton instance, rather than an + * auto_ptr. This is done b/c there is a valid use case the auto_ptr + * gets destroyed (as well as the underlying memory), but if the Singleton + * gets revived, the auto_ptr does NOT get recreated, and returns an invalid + * memory address. + * + */ +template struct SingletonAutoDestroyer +{ + static void registerAtExit(void (*)(void)) + { + /* When AutoDestroy is false, we want to do nothing */ + } +}; + +template <> struct SingletonAutoDestroyer +{ + static void registerAtExit(void (*function)(void)) + { +#if defined(__SunOS_5_10) +/* + * Fix for Solaris bug where atexit is not extern C++ + * http://bugs.opensolaris.org/bugdatabase/view_bug.do;jsessionid=9c8c03419fb896b730de20cd53ae?bug_id=6455603 + */ +# if !defined(ELIMINATE_BROKEN_LINKAGE) + atexit(function); +# endif +#else + std::atexit(function); +#endif + } +}; + +template +class Singleton +{ +public: + /*! + * Returns the one and only instance of the object + */ + static T& getInstance(); + + /*! + * This attempts to destroy the internal singleton object. If it has + * already been destroyed, it does nothing. Usually you only should + * call this method if AutoDestroy is set to false. Otherwise, this method + * will get automatically called at program exit. + */ + static void destroy(); + +protected: + //! Constructor + inline explicit Singleton() + { + assert(mInstance == 0); + mInstance = static_cast(this); + } + //! Destructor + inline ~Singleton() { mInstance = 0; } + +private: + static T* mInstance; //static instance + static sys::Mutex mMutex; //static mutex for locking access to the instance + inline explicit Singleton(Singleton const&) {} + inline Singleton& operator=(Singleton const&) { return *this; } +}; + +template +T& Singleton::getInstance() +{ + //double-checked locking + if (mInstance == 0) + { + CriticalSection obtainLock(&mMutex); + if (mInstance == 0) + { + mInstance = new T; //create the instance + SingletonAutoDestroyer::registerAtExit(destroy); + } + } + return *mInstance; +} + +template +void Singleton::destroy() +{ + //double-checked locking + if (mInstance != 0) + { + CriticalSection obtainLock(&mMutex); + if (mInstance != 0) + { + //we are OK to delete it + delete mInstance; + mInstance = 0; + } + } +} + +template T* Singleton::mInstance = 0; +template sys::Mutex Singleton::mMutex; + +} +#endif diff --git a/modules/c++/mt/include/mt/ThreadGroup.h b/modules/c++/mt/include/mt/ThreadGroup.h new file mode 100644 index 000000000..c2a340ec4 --- /dev/null +++ b/modules/c++/mt/include/mt/ThreadGroup.h @@ -0,0 +1,81 @@ +/* ========================================================================= + * This file is part of mt-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * mt-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __MT_THREAD_GROUP_H__ +#define __MT_THREAD_GROUP_H__ + +#include +#include +#include "sys/Runnable.h" +#include "sys/Thread.h" +#include "mem/SharedPtr.h" +#include "except/Error.h" + +namespace mt +{ + +/*! + * \class ThreadGroup + * + * \brief Basic thread group. + * + * This class is a basic thread group that can create threads from + * sys::Runnable objects and wait for all threads to complete. + * + */ + +class ThreadGroup +{ +public: + + //! Constructor. + ThreadGroup(); + + /*! + * Destructor. Attempts to join all threads. + */ + ~ThreadGroup(); + + /*! + * Creates and starts a thread from a sys::Runnable. + * \param runnable pointer to sys::Runnable + */ + void createThread(sys::Runnable *runnable); + + /*! + * Creates and starts a thread from a sys::Runnable. + * \param runnable auto_ptr to sys::Runnable + */ + void createThread(std::auto_ptr runnable); + + /*! + * Waits for all threads to complete. + */ + void joinAll(); + +private: + std::vector > mThreads; + size_t mLastJoined; +}; +} + +#endif diff --git a/modules/c++/mt/include/mt/ThreadPlanner.h b/modules/c++/mt/include/mt/ThreadPlanner.h new file mode 100644 index 000000000..622c019f2 --- /dev/null +++ b/modules/c++/mt/include/mt/ThreadPlanner.h @@ -0,0 +1,66 @@ +/* ========================================================================= + * This file is part of mt-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2013, General Dynamics - Advanced Information Systems + * + * mt-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __MT_THREAD_PLANNER_H__ +#define __MT_THREAD_PLANNER_H__ + +#include + +namespace mt +{ + class ThreadPlanner + { + private: + size_t mNumElements; + size_t mNumThreads; + size_t mNumElementsPerThread; + public: + ThreadPlanner(size_t numElements, size_t numThreads) : + mNumElements(numElements), mNumThreads(numThreads) + { + mNumElementsPerThread = (mNumElements / mNumThreads) + (mNumElements % mNumThreads != 0); + } + + size_t getNumElementsPerThread() const + { + return mNumElementsPerThread; + } + + bool getThreadInfo(size_t threadNum, size_t& startElement, size_t& numElementsThisThread) const + { + startElement = threadNum * mNumElementsPerThread; + if(startElement > mNumElements) + { + numElementsThisThread = 0; + } + else + { + size_t numElementsRemaining = mNumElements - startElement; + numElementsThisThread = std::min(mNumElementsPerThread, numElementsRemaining); + } + return (numElementsThisThread != 0); + } + }; +} + +#endif + diff --git a/modules/c++/mt/include/mt/ThreadPoolException.h b/modules/c++/mt/include/mt/ThreadPoolException.h new file mode 100644 index 000000000..9a65efe94 --- /dev/null +++ b/modules/c++/mt/include/mt/ThreadPoolException.h @@ -0,0 +1,69 @@ +/* ========================================================================= + * This file is part of mt-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * mt-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __MT_THREAD_POOL_EXCEPTION_H__ +#define __MT_THREAD_POOL_EXCEPTION_H__ + +#include "except/Exception.h" + +namespace mt +{ +class ThreadPoolException : public except::Exception +{ +public: + //! Default Constructor + ThreadPoolException() + {} + + /*! + * User constructor. Sets the exception message. + * \param message the exception message + */ + ThreadPoolException(const char *message) : + except::Exception(message) + {} + + /*! + * User constructor. Sets the exception message. + * \param message the exception message + */ + ThreadPoolException(const std::string& message) : + except::Exception(message) + {} + + /*! + * User constructor. Sets the exception context. + * \param c the exception context + */ + ThreadPoolException(const except::Context& c) : + except::Exception(c) + {} + + //! Destructor + virtual ~ThreadPoolException() + {} +} +; +} + +#endif diff --git a/modules/c++/mt/include/mt/TiedWorkerThread.h b/modules/c++/mt/include/mt/TiedWorkerThread.h new file mode 100644 index 000000000..8329b445c --- /dev/null +++ b/modules/c++/mt/include/mt/TiedWorkerThread.h @@ -0,0 +1,71 @@ +/* ========================================================================= + * This file is part of mt-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * mt-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __MT_TIED_WORKER_THREAD_H__ +#define __MT_TIED_WORKER_THREAD_H__ + +#include "mt/CPUAffinityThreadInitializer.h" + + +namespace mt +{ + +/** + * @created 03-Jan-2007 12:51:46 + */ +template +class TiedWorkerThread : public mt::WorkerThread +{ +public: + TiedWorkerThread(mt::RequestQueue* requestQueue, + CPUAffinityThreadInitializer* cpuAffinityInit = NULL): + mt::WorkerThread(requestQueue), + mCPUAffinityInit(cpuAffinityInit){} + + virtual ~TiedWorkerThread() + { + if (mCPUAffinityInit) + { + delete mCPUAffinityInit; + mCPUAffinityInit = NULL; + } + } + + virtual void initialize() + { + if (mCPUAffinityInit) + { + mCPUAffinityInit->initialize(); + } + } + + virtual void performTask(Request_T& request) = 0; + +private: + TiedWorkerThread(); + CPUAffinityThreadInitializer* mCPUAffinityInit; +}; + +} +#endif + diff --git a/modules/c++/mt/include/mt/WorkerThread.h b/modules/c++/mt/include/mt/WorkerThread.h new file mode 100644 index 000000000..ee7cda3e3 --- /dev/null +++ b/modules/c++/mt/include/mt/WorkerThread.h @@ -0,0 +1,108 @@ +/* ========================================================================= + * This file is part of mt-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * mt-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __WORKER_THREAD_H__ +#define __WORKER_THREAD_H__ + + +#include "sys/Thread.h" +#include "mt/RequestQueue.h" +#include "str/Convert.h" + + + +namespace mt +{ +/*! + * \class WorkerThread + * \brief Virtual class for thread pool + * + * A WorkerThread object is the basic underlying thread for + * AbstractThreadPool, a partially implemented pool of threads + * operating on a consumer-producer buffer. This class can be + * implemented by deriving the performTask function. The thread + * runs until the program is stopped. + */ +template class WorkerThread : public sys::Thread +{ +public: + //! Constructor + WorkerThread(mt::RequestQueue* requestQueue) : + mRequestQueue(requestQueue), mDone(false) + {} + + /*! + * Virtual destructor + */ + virtual ~WorkerThread() + {} + + virtual void initialize() + {} + /*! + * Run this request + */ + virtual void run() + { + initialize(); + while (!isDone()) + { + // Pull a runnable off the queue + Request_T req; + mRequestQueue->dequeue(req); + performTask(req); + } + } + virtual bool isDone() const + { + return mDone; + } + virtual void setDone() + { + mDone = true; + } + /*! + * Virtual function to perform work on a request. + * This function must be overriden by the derived class. + * + * \param request A request from the queue + */ + virtual void performTask(Request_T& request) = 0; + + /*! + * Produces the system-named thread ID + * \todo Remove? + * + */ + std::string getThreadId() + { + return str::toString(sys::getThreadID()); + } +protected: + + mt::RequestQueue *mRequestQueue; + bool mDone; +}; +} + +#endif diff --git a/modules/c++/mt/source/GenerationThreadPool.cpp b/modules/c++/mt/source/GenerationThreadPool.cpp new file mode 100644 index 000000000..bc1193058 --- /dev/null +++ b/modules/c++/mt/source/GenerationThreadPool.cpp @@ -0,0 +1,104 @@ +/* ========================================================================= + * This file is part of mt-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * mt-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#include "mt/GenerationThreadPool.h" +#if !defined(__APPLE_CC__) + +mt::TiedRequestHandler::~TiedRequestHandler() +{ + if (mAffinityInit) + { + delete mAffinityInit; + mAffinityInit = NULL; + } + +} + +// If we have a thread initializer, tie down our handler to a CPU +void mt::TiedRequestHandler::initialize() +{ + if (mAffinityInit) + { + mAffinityInit->initialize(); + } +} +void mt::TiedRequestHandler::run() +{ + // Call our init (gets called from within the thread package's create fn) + initialize(); + + while (true) + { + // Pull a runnable off the queue + sys::Runnable *handler = NULL; + + mRequestQueue->dequeue(handler); + if (!handler) return; + + // Run the runnable that we pulled off the queue + handler->run(); + + // Delete the runnable we pulled off the queue + delete handler; + + // Signal to the thread pool that we are done + // This will allow 1 wait() to complete + mSem->signal(); + } +} + +// Not set up for multiple producers +void mt::GenerationThreadPool::addGroup(std::vector& toRun) +{ + + if (mGenSize) + throw mt::ThreadPoolException(Ctxt("The previous generation has not completed!")); + + mGenSize = toRun.size(); + for (int i = 0; i < mGenSize; ++i) + addRequest(toRun[i]); +} + +// Not set up for multiple producers +void mt::GenerationThreadPool::waitGroup() +{ + while (mGenSize) + { + mGenerationSync.wait(); + //std::cout << "Waited" << std::endl; + --mGenSize; + } +} + +/*void mt::GenerationThreadPool::shutdown() +{ + size_t size = mPool.size(); + static sys::Runnable* shutdown = NULL; + for(unsigned int i=0; i < size; i++) + { + addRequest(shutdown); + } +}*/ + +#endif + diff --git a/modules/c++/mt/source/GenericRequestHandler.cpp b/modules/c++/mt/source/GenericRequestHandler.cpp new file mode 100644 index 000000000..237e399d0 --- /dev/null +++ b/modules/c++/mt/source/GenericRequestHandler.cpp @@ -0,0 +1,45 @@ +/* ========================================================================= + * This file is part of mt-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * mt-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include + +#include "mt/GenericRequestHandler.h" + +void mt::GenericRequestHandler::run() +{ + while (true) + { + // Pull a runnable off the queue + sys::Runnable* handler = NULL; + mRequest->dequeue(handler); + if (!handler) + { + return; + } + + // Run the runnable that we pulled off the queue + // It will get deleted when it goes out of scope below + std::auto_ptr scopedHandler(handler); + scopedHandler->run(); + } +} + diff --git a/modules/c++/mt/source/LinuxCPUAffinityInitializer.cpp b/modules/c++/mt/source/LinuxCPUAffinityInitializer.cpp new file mode 100644 index 000000000..4a6905bd5 --- /dev/null +++ b/modules/c++/mt/source/LinuxCPUAffinityInitializer.cpp @@ -0,0 +1,39 @@ +/* ========================================================================= + * This file is part of mt-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * mt-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#include "mt/LinuxCPUAffinityInitializer.h" + +#if !defined(__APPLE_CC__) +#if defined(__linux) || defined(__linux__) + +cpu_set_t mt::LinuxCPUAffinityInitializer::nextCPU() +{ + cpu_set_t affinityMask; + CPU_ZERO(&affinityMask); + CPU_SET(mNextCPU, &affinityMask); + ++mNextCPU; + return affinityMask; +} + +#endif +#endif diff --git a/modules/c++/mt/source/LinuxCPUAffinityThreadInitializer.cpp b/modules/c++/mt/source/LinuxCPUAffinityThreadInitializer.cpp new file mode 100644 index 000000000..0af271938 --- /dev/null +++ b/modules/c++/mt/source/LinuxCPUAffinityThreadInitializer.cpp @@ -0,0 +1,54 @@ +/* ========================================================================= + * This file is part of mt-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * mt-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#include "mt/LinuxCPUAffinityThreadInitializer.h" + +#if !defined(__APPLE_CC__) +#if defined(__linux) || defined(__linux__) + +mt::LinuxCPUAffinityThreadInitializer:: +LinuxCPUAffinityThreadInitializer(const cpu_set_t& cpu) +{ + for (int i = 0; i < CPU_SETSIZE; ++i) + { + CPU_CLR(i, &mCPU); + if (CPU_ISSET(i, &cpu)) + CPU_SET(i, &mCPU); + } + +} + +void mt::LinuxCPUAffinityThreadInitializer::initialize() +{ + pid_t tid = 0; + tid = ::gettid(); + if ( ::sched_setaffinity(tid, sizeof(mCPU), &mCPU) == -1 ) + { + sys::Err e; + std::ostringstream errStr; + errStr << "Failed setting processor affinity: " << e.toString(); + throw except::Exception(Ctxt(errStr.str())); + } +} +#endif +#endif diff --git a/modules/c++/mt/source/ThreadGroup.cpp b/modules/c++/mt/source/ThreadGroup.cpp new file mode 100644 index 000000000..8e8f7d4ef --- /dev/null +++ b/modules/c++/mt/source/ThreadGroup.cpp @@ -0,0 +1,73 @@ +/* ========================================================================= + * This file is part of mt-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * mt-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include "mt/ThreadGroup.h" + +mt::ThreadGroup::ThreadGroup() : + mLastJoined(0) +{ +} + +mt::ThreadGroup::~ThreadGroup() +{ + try + { + joinAll(); + } + catch (...) + { + // Make sure we don't throw out of the destructor. + } +} + +void mt::ThreadGroup::createThread(sys::Runnable *runnable) +{ + createThread(std::auto_ptr(runnable)); +} + +void mt::ThreadGroup::createThread(std::auto_ptr runnable) +{ + mem::SharedPtr thread(new sys::Thread(runnable.get())); + runnable.release(); + mThreads.push_back(thread); + thread->start(); +} + +void mt::ThreadGroup::joinAll() +{ + bool failed = false; + // Keep track of which threads we've already joined. + for (; mLastJoined < mThreads.size(); mLastJoined++) + { + try + { + mThreads[mLastJoined]->join(); + } + catch (...) + { + failed = true; + } + } + + if (failed) + throw except::Error(Ctxt("ThreadGroup could not be joined")); +} diff --git a/modules/c++/mt/tests/BasicThreadPoolTest.cpp b/modules/c++/mt/tests/BasicThreadPoolTest.cpp new file mode 100644 index 000000000..f7be6755c --- /dev/null +++ b/modules/c++/mt/tests/BasicThreadPoolTest.cpp @@ -0,0 +1,98 @@ +/* ========================================================================= + * This file is part of mt-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * mt-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#if defined(__APPLE_CC__) +#include +int main (int argc, char *argv[]) +{ + std::cout << "Sorry no semaphores" << std::endl; + return 0; +} + +#else +#include +#include +#include +using namespace sys; +using namespace mt; +using namespace std; + +const int NUM_TASKS = 5; +const int TO_SLEEP = 2; + +class MyRunTask : public Runnable +{ + Semaphore& mSem; +public: + MyRunTask(Semaphore& sem) : + mSem(sem) + { + } + virtual ~MyRunTask() + { + } + + virtual void run() + { + sleep(TO_SLEEP); + mSem.signal(); + } +}; + +int main(int argc, char *argv[]) +{ + try + { + // Semaphore inited at 0 + Semaphore sem; + + // Create a thread pool of size 2 + BasicThreadPool < GenericRequestHandler > pool(2); + + for (int i = 0; i < NUM_TASKS; i++) + { + pool.addRequest(new MyRunTask(sem)); + } + pool.start(); + + for (int i = 0; i < NUM_TASKS; i++) + { + sem.wait(); + } + + std::cout << "Finished all" << std::endl; + + } + + catch (except::Throwable& t) + { + cout << "Exception Caught: " << t.toString() << endl; + } + catch (...) + { + cout << "Exception Caught!" << endl; + return -1; + } + + return 0; +} +#endif diff --git a/modules/c++/mt/tests/GenerationThreadPoolTest.cpp b/modules/c++/mt/tests/GenerationThreadPoolTest.cpp new file mode 100644 index 000000000..80f2f9b06 --- /dev/null +++ b/modules/c++/mt/tests/GenerationThreadPoolTest.cpp @@ -0,0 +1,100 @@ +/* ========================================================================= + * This file is part of mt-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * mt-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#if defined(__APPLE_CC__) +#include +int main (int argc, char *argv[]) +{ + std::cout << "Sorry no semaphores" << std::endl; + return 0; +} + +#else +#include "mt/GenerationThreadPool.h" +#include "mt/CriticalSection.h" + +using namespace mt; +using namespace sys; +const int TO_SLEEP = 2; +const int NUM_GENS = 3; +sys::Mutex gLock; + +class MyRunTask : public sys::Runnable +{ + int mI; +public: + MyRunTask(int i) : + mI(i) + { + } + ~MyRunTask() + { + } + + void run() + { + sleep(TO_SLEEP); + + // Goes out of scope when we finish printing and return + mt::CriticalSection < sys::Mutex > cs(&gLock); + std::cout << "Run " << mI << " completed" << std::endl; + + } +}; + +void runGeneration(GenerationThreadPool& pool) +{ + static int nRunsInGen = 1; + + std::vector runs; + for (int i = 0; i < nRunsInGen; i++) + { + runs.push_back(new MyRunTask(i)); + } + + pool.addAndWaitGroup(runs); + std::cout << "Generation done" << std::endl; + nRunsInGen++; + +} +int main() +{ + try + { + // Create a thread pool of size 4 + GenerationThreadPool pool(4); + // Start it + pool.start(); + + for (int i = 0; i < NUM_GENS; i++) + runGeneration(pool); + + pool.shutdown(); + pool.join(); + } + catch (except::Exception& ex) + { + std::cout << "Caught exception: " << ex.toString() << std::endl; + std::cout << "\t" << ex.getTrace() << std::endl; + } +} +#endif diff --git a/modules/c++/mt/tests/MTSingletonTest.cpp b/modules/c++/mt/tests/MTSingletonTest.cpp new file mode 100644 index 000000000..7dadee6a4 --- /dev/null +++ b/modules/c++/mt/tests/MTSingletonTest.cpp @@ -0,0 +1,254 @@ +/* ========================================================================= + * This file is part of mt-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * mt-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ +#if defined(__APPLE_CC__) +#include +int main (int argc, char *argv[]) +{ + std::cout << "Sorry no semaphores" << std::endl; + return 0; +} + +#else + +#include +#include +#include +#include + +using namespace except; +using namespace sys; +using namespace std; +using namespace mt; + +class StopsWhenEmpty : public GenericRequestHandler +{ +public: + StopsWhenEmpty(RunnableRequestQueue* request) : + GenericRequestHandler(request) + { + } + + ~StopsWhenEmpty() + { + } + + void run() + { + while (true) + { + + if (mRequest->isEmpty()) + { + cout << "exiting run()" << endl; + return; + } + + // Pull a runnable off the queue + Runnable *handler; + mRequest->dequeue(handler); + + // Run the runnable that we pulled off the queue + handler->run(); + + // Delete the runnable we pulled off the queue + delete handler; + + } + } +}; + +/*class ChangeRequest : public Runnable + { + public: + ChangeRequest(HandlerInterface* newHandler) : mNH(newHandler) {} + ~ChangeRequest() {} + void run() + { + StatusHandler().changeHandler(mNH); + //__status__("Changed the singleton handler"); + } + protected: + HandlerInterface *mNH; + + };*/ + +class Thespian : public Runnable +{ +public: + Thespian(const char* name) : + mName(name) + { + } + virtual ~Thespian() + { + } + void run() + { + //__debugln__(FmtX("[%s]:", mName.c_str())); + doLines(); + } + virtual void doLines() = 0; +protected: + std::string mName; +}; + +class Soothsayer : public Thespian +{ +public: + Soothsayer() : + Thespian("Soothsayer") + { + } + ~Soothsayer() + { + } + + void doLines() + { + //__warning__("Beware the ides of March."); + } +}; + +class Calpurnia : public Thespian +{ +public: + Calpurnia() : + Thespian("Calpurnia") + { + } + ~Calpurnia() + { + } + void doLines() + { + //__warning__("Caesar, I never stood on ceremonies, Yet now they fright me. There is one within, 15 Besides the things that we have heard and seen, Recounts most horrid sights seen by the watch. A lioness hath whelped in the streets; And graves have yawn'd, and yielded up their dead; Fierce fiery warriors fought upon the clouds, 20 In ranks and squadrons and right form of war, Which drizzled blood upon the Capitol; The noise of battle hurtled in the air, Horses did neigh, and dying men did groan, And ghosts did shriek and squeal about the streets. 25 O Caesar! these things are beyond all use, And I do fear them."); + } + +}; +class Caesar : public Thespian +{ +public: + Caesar() : + Thespian("Caesar") + { + } + ~Caesar() + { + } + void doLines() + { + //__status__("Cowards die many times before their deaths; The valiant never taste of death but once. 35 Of all the wonders that I yet have heard. It seems to me most strange that men should fear; Seeing that death, a necessary end, Will come when it will come."); + } + +}; + +class Brutus : public Thespian +{ +public: + Brutus() : + Thespian("Brutus") + { + } + virtual ~Brutus() + { + } + + virtual void doLines() + { + //__status__("Be patient till the last. Romans, countrymen, and lovers! hear me for my 15 cause, and be silent, that you may hear: believe me for mine honour, and have respect to mine honour, that you may believe: censure me in your wisdom, and awake your senses, that you may the better judge. If there be any in this assembly, any dear friend of 20 Caesar's, to him I say, that Brutus' love to Caesar was no less than his. If then that friend demand why Brutus rose against Caesar, this is my answer: --Not that I loved Caesar less, but that I loved Rome more. Had you rather Caesar were living and 25 die all slaves, than that Caesar were dead, to live all free men? As Caesar loved me, I weep for him; as he was fortunate, I rejoice at it; as he was valiant, I honour him: but, as he was ambitious, I slew him. There is tears for his love; joy for his 30 fortune; honour for his valour; and death for his ambition. Who is here so base that would be a bondman? If any, speak; for him have I offended. Who is here so rude that would not be a Roman? If any, speak; for him have I offended. Who is here so 35 vile that will not love his country? If any, speak; for him have I offended. I pause for a reply."); + + } +}; + +class Antony : public Thespian +{ +public: + Antony() : + Thespian("Antony") + { + } + ~Antony() + { + } + + void doLines() + { + //__status__("Villains, you did not so, when your vile daggers Hack'd one another in the sides of Caesar: You show'd your teeth like apes, and fawn'd like hounds, 45 And bow'd like bondmen, kissing Caesar's feet; Whilst damned Casca, like a cur, behind Struck Caesar on the neck. O you flatterers!"); + } +}; + +class Octavius : public Thespian +{ +public: + Octavius() : + Thespian("Ocativius") + { + } + ~Octavius() + { + } + + void doLines() + { + //__status__("According to his virtue let us use him, With all respect and rites of burial. Within my tent his bones to-night shall lie, 85 Most like a soldier, order'd honourably. So call the field to rest; and let's away, To part the glories of this happy day."); + } +}; + +int main(int argc, char *argv[]) +{ + try + { + BasicThreadPoolpool(2); + + // pool.addRequest(new ChangeRequest( + // new LogExHandler( + // new StandardErrStream() + // ) + // ) + // ); + pool.addRequest(new Soothsayer()); + pool.addRequest(new Calpurnia()); + + // pool.addRequest(new ChangeRequest(new LogExHandler(new StandardOutStream()))); + + pool.addRequest(new Caesar()); + pool.addRequest(new Brutus()); + pool.addRequest(new Antony()); + pool.addRequest(new Octavius()); + + pool.start(); + pool.join(); + } + catch (except::Throwable& t) + { + cout << "Exception Caught: " << t.toString() << endl; + } + catch (...) + { + cout << "Exception Caught!" << endl; + return -1; + } + + return 0; +} + +#endif diff --git a/modules/c++/mt/tests/SingletonTest.cpp b/modules/c++/mt/tests/SingletonTest.cpp new file mode 100644 index 000000000..cf9d39194 --- /dev/null +++ b/modules/c++/mt/tests/SingletonTest.cpp @@ -0,0 +1,63 @@ +/* ========================================================================= + * This file is part of mt-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * mt-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#if defined(__APPLE_CC__) +#include +int main (int argc, char *argv[]) +{ + std::cout << "Sorry no semaphores" << std::endl; + return 0; +} + +#else +#include +#include +#include + +using namespace sys; +using namespace mt; + +class Counter +{ +public: + Counter() : mCnt(0) { } + ~Counter() { } + void sayCount() { std::cout << "Count: " << ++mCnt << std::endl; } +protected: + int mCnt; +}; + +typedef Singleton AutoIncrementer; + +int main (int argc, char *argv[]) +{ + AutoIncrementer::getInstance().sayCount(); + AutoIncrementer::getInstance().sayCount(); + AutoIncrementer::getInstance().sayCount(); + AutoIncrementer::getInstance().sayCount(); + AutoIncrementer::getInstance().sayCount(); + AutoIncrementer::getInstance().sayCount(); + + return 0; +} + +#endif diff --git a/modules/c++/mt/tests/TwoSingletonsTest.cpp b/modules/c++/mt/tests/TwoSingletonsTest.cpp new file mode 100644 index 000000000..4db5fe19d --- /dev/null +++ b/modules/c++/mt/tests/TwoSingletonsTest.cpp @@ -0,0 +1,91 @@ +/* ========================================================================= + * This file is part of mt-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * mt-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#if defined(__APPLE_CC__) +#include +int main (int argc, char *argv[]) +{ + std::cout << "Sorry no semaphores" << std::endl; + return 0; +} +#else + +#include +#include +#include +#include + +using namespace sys; +using namespace mt; + +class Logger +{ +private: + int num; + sys::Mutex mutex; +public: + Logger():num(0){ std::cout << "In Logger Constructor." << std::endl; } + ~Logger(){ std::cout << "In Logger Destructor." << std::endl; } + void log(std::string msg) + { + mt::CriticalSection obtainLock(&mutex); + std::cout << "INFO[" << num++ << "]: " << msg << std::endl; + } +}; +typedef Singleton LoggerFactory; //this gets deleted at exit + + +class Counter +{ +public: + Counter() : mCnt(0) { std::cout << "In Counter Constructor." << std::endl; } + ~Counter() + { + LoggerFactory::getInstance().log("In Counter Destructor."); + } + void sayCount() + { + std::ostringstream os; + os << "Count: " << ++mCnt; + LoggerFactory::getInstance().log(os.str()); + } +protected: + int mCnt; +}; +typedef Singleton AutoIncrementer; //this does NOT get deleted at exit + + +int main (int argc, char *argv[]) +{ + AutoIncrementer::getInstance().sayCount(); + AutoIncrementer::getInstance().sayCount(); + AutoIncrementer::getInstance().sayCount(); + AutoIncrementer::getInstance().sayCount(); + AutoIncrementer::getInstance().sayCount(); + AutoIncrementer::getInstance().sayCount(); + LoggerFactory::getInstance().log("Main end"); + AutoIncrementer::destroy(); + return 0; +} + +#endif + diff --git a/modules/c++/mt/unittests/Runnable1DTest.cpp b/modules/c++/mt/unittests/Runnable1DTest.cpp new file mode 100644 index 000000000..8e5d9041b --- /dev/null +++ b/modules/c++/mt/unittests/Runnable1DTest.cpp @@ -0,0 +1,101 @@ +/* ========================================================================= + * This file is part of mt-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2013, General Dynamics - Advanced Information Systems + * + * mt-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include +#include + +#include "import/sys.h" +#include "import/mt.h" +#include "TestCase.h" + +using namespace sys; +using namespace mt; +using namespace std; + +namespace +{ +class AddOp +{ +public: + AddOp() + { + } + + void operator()(size_t element) const + { + std::ostringstream ostr; + ostr << element << std::endl; + + // This SHOULD result in not getting the printouts garbled between + // threads + ::fprintf(stderr, "%s", ostr.str().c_str()); + } +}; + +class LocalStorage +{ +public: + LocalStorage() : + mValue(0) + { + } + + void operator()(size_t element) const + { + // All we're really showing here is that we never print out the same + // value twice due to the threads colliding + mValue = element; + std::ostringstream ostr; + ostr << mValue << std::endl; + ::fprintf(stderr, "%s", ostr.str().c_str()); + } + +private: + mutable size_t mValue; +}; + +TEST_CASE(Runnable1DTest) +{ + std::cout << "Running test case" << std::endl; + const AddOp op; + std::cout << "Calling run1D" << std::endl; + run1D(10, 16, op); +} + +TEST_CASE(Runnable1DWithCopiesTest) +{ + // TODO: Have LocalStorage actually store its values off in a vector, then + // show we got all those values. + std::cout << "Running test case" << std::endl; + const LocalStorage op; + std::cout << "Calling run1D" << std::endl; + run1DWithCopies(47, 16, op); +} +} + +int main(int argc, char *argv[]) +{ + TEST_CHECK(Runnable1DTest); + TEST_CHECK(Runnable1DWithCopiesTest); + + return 0; +} diff --git a/modules/c++/mt/unittests/ThreadGroupTest.cpp b/modules/c++/mt/unittests/ThreadGroupTest.cpp new file mode 100644 index 000000000..aa0ed10e1 --- /dev/null +++ b/modules/c++/mt/unittests/ThreadGroupTest.cpp @@ -0,0 +1,88 @@ +/* ========================================================================= + * This file is part of mt-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * mt-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include "import/sys.h" +#include "import/mt.h" +#include "TestCase.h" + +using namespace sys; +using namespace mt; +using namespace std; + +class MyRunTask : public Runnable +{ +public: + int result; + int *state; + int *num_deleted; + + MyRunTask(int *new_state, int *new_num_deleted) + { + state = new_state; + result = *new_state; + num_deleted = new_num_deleted; + } + virtual ~MyRunTask() + { + (*num_deleted)++; + } + + virtual void run() + { + while (result == 1) + result = *state; + } +}; + +TEST_CASE(ThreadGroupTest) +{ + ThreadGroup *threads = new ThreadGroup(); + int state = 1, numDeleted = 0; + MyRunTask *tasks[3]; + + for (int i = 0; i < 3; i++) + tasks[i] = new MyRunTask(&state, &numDeleted); + + threads->createThread(tasks[0]); + threads->createThread(tasks[1]); + state = 2; + threads->joinAll(); + + TEST_ASSERT_EQ(tasks[0]->result, 2); + TEST_ASSERT_EQ(tasks[1]->result, 2); + + state = 1; + threads->createThread(tasks[2]); + state = 3; + + TEST_ASSERT_EQ(numDeleted, 0); + + delete threads; + TEST_ASSERT_EQ(numDeleted, 3); +} + +int main(int argc, char *argv[]) +{ + TEST_CHECK(ThreadGroupTest); + + return 0; +} diff --git a/modules/c++/mt/unittests/ThreadPlannerTest.cpp b/modules/c++/mt/unittests/ThreadPlannerTest.cpp new file mode 100644 index 000000000..c8b40c988 --- /dev/null +++ b/modules/c++/mt/unittests/ThreadPlannerTest.cpp @@ -0,0 +1,58 @@ +/* ========================================================================= + * This file is part of mt-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2013, General Dynamics - Advanced Information Systems + * + * mt-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include "import/sys.h" +#include "import/mt.h" +#include "TestCase.h" + +using namespace sys; +using namespace mt; +using namespace std; + +TEST_CASE(ThreadPlannerTest) +{ + size_t numThreads(16); + ThreadPlanner planner(500, numThreads); + std::cout << "Num Elements Per Thread: " << planner.getNumElementsPerThread() << std::endl; + size_t startElement(0); + size_t numElements(0); + for(size_t i=0; i < numThreads; ++i) + { + planner.getThreadInfo(i, startElement, numElements); + std::cout << "Thread: " << i << " Start: " << startElement << " Num: " << numElements << std::endl; + if(i == numThreads-1) + { + TEST_ASSERT_EQ(numElements, 20) + } + else + { + TEST_ASSERT_EQ(numElements, 32) + } + } +} + +int main(int argc, char *argv[]) +{ + TEST_CHECK(ThreadPlannerTest); + + return 0; +} diff --git a/modules/c++/mt/wscript b/modules/c++/mt/wscript new file mode 100644 index 000000000..80df1c3fc --- /dev/null +++ b/modules/c++/mt/wscript @@ -0,0 +1,9 @@ +NAME = 'mt' +MAINTAINER = 'jmrandol@users.sourceforge.net' +VERSION = '1.1' +MODULE_DEPS = 'sys except mem' + +options = configure = distclean = lambda p: None + +def build(bld): + bld.module(**globals()) diff --git a/modules/c++/nitf/Makefile.in b/modules/c++/nitf/Makefile.in new file mode 100755 index 000000000..5a5f7f159 --- /dev/null +++ b/modules/c++/nitf/Makefile.in @@ -0,0 +1,71 @@ +# ========================================================================= +# This file is part of NITRO +# ========================================================================= +# +# (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems +# +# NITRO is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, If not, +# see . +# + +#---------------------------------------- +# General area +#---------------------------------------- +include ./build/project.make + +#---------------------------------------- +# Build rules +#---------------------------------------- + + +#---------------------------------------- +# This is specified by the user in the +# project.make. It is a space delimited +# set of rules +#---------------------------------------- + +all: library unit-tests progs + +library: + cd source; make + +unit-tests: + cd tests; make + +progs: + cd apps; make + +clean: + cd source; make clean + cd tests; make clean + cd apps; make clean + rm -rf lib; rm -rf bin + +raw: clean + cd source; make raw + cd tests; make raw + cd apps; make raw + cd build; rm -f Makefile; rm -f project.make + rm -f Makefile + + +dist: + perl @build_dir@/makedist.pl $(PACKAGE) $(VERSION) @target@ + +copy: dist + mkdir -p @prefix@ + mv $(PACKAGE)_$(VERSION)_@target@.tar @prefix@/ + +install: copy + cd @prefix@; tar -xvf $(PACKAGE)_$(VERSION)_@target@.tar; \rm -f $(PACKAGE)_$(VERSION)_@target@.tar diff --git a/modules/c++/nitf/README.txt b/modules/c++/nitf/README.txt new file mode 100644 index 000000000..5b50082b4 --- /dev/null +++ b/modules/c++/nitf/README.txt @@ -0,0 +1,3 @@ +This library wraps the original C library (located in projects/nitf). It uses +a base Object class that contains a handle that performs reference counting on +the underlying C objects to ensure proper memory allocation/deallocation. diff --git a/modules/c++/nitf/apps/Makefile.in b/modules/c++/nitf/apps/Makefile.in new file mode 100644 index 000000000..cbdd4816c --- /dev/null +++ b/modules/c++/nitf/apps/Makefile.in @@ -0,0 +1,55 @@ +# ========================================================================= +# This file is part of NITRO +# ========================================================================= +# +# (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems +# +# NITRO is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, If not, +# see . +# + +#---------------------------------------- +# General area +#---------------------------------------- +include ../build/Makefile + +EXE = $(APPS:.cpp=) +OBJS = ${APPS:.cpp=.o} +#---------------------------------------- +# Build commands +#---------------------------------------- +all: $(EXE) + +$(EXE): $(OBJS) dirs + $(COMPILE) -o $@ $@.o $(LINK) + mv $@ $(TESTDIR) + +#---------------------------------------- +# Rule for setting up dir. structure +#---------------------------------------- +dirs: + \mkdir -p $(TESTDIR) + + +.SUFFIXES: .o .cpp +.cpp.o: + $(COMPILE) -c $? + +clean: + \rm -f $(OBJS) + \rm -rf $(TESTDIR) + +raw: clean + \rm -f Makefile + diff --git a/modules/c++/nitf/apps/show_nitf++.cpp b/modules/c++/nitf/apps/show_nitf++.cpp new file mode 100644 index 000000000..4873f28ab --- /dev/null +++ b/modules/c++/nitf/apps/show_nitf++.cpp @@ -0,0 +1,702 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + +#define SHOW(X) std::cout << #X << " = [" << X << "]" << std::endl +#define SHOWI(X) printf("%s=[%d]\n", #X, (int)X) +#define SHOWRGB(X) printf("%s(R,G,B)=[%02x,%02x,%02x]\n", #X, \ + (unsigned char) X[0], (unsigned char) X[1], (unsigned char) X[2]) + + +/* + * This function dumps a TRE using the TRE iterator (enumerator in C). + * The iterator is used to walk the fields of a TRE in order + * when the TRE enumerator is expired it will be set to NULL. + * + */ + +void printTRE(nitf::TRE tre) +{ + + + + // This is so you know how long the TRE is + nitf_Uint32 treLength = tre.getCurrentSize(); + + /* + * This is the name for the description that was selected to field + * this TRE by the handler. + */ + std::string treID = tre.getID(); + + + std::cout << std::endl << "--------------- " << tre.getTag() + << " TRE (" << treLength << " - " + << (treID.empty() ? "nullID" : treID) + << ") ---------------" << std::endl; + + // Now walk the TRE + for(nitf::TRE::Iterator it = tre.begin(); it != tre.end(); ++it) + { + std::string desc = it.getFieldDescription(); + nitf::Field field((*it).second()); + std::cout << (*it).first(); + if (!desc.empty()) + std::cout << " (" << desc << ")"; + std::cout << " = [" + << field.toString() << "]" << std::endl; + } + std::cout << "---------------------------------------------" << std::endl; + +} + +/* + * This function shows us the best way of walking through + * an extension segment (userDefined or extended) + */ +void showExtensions(nitf::Extensions extensions) +{ + for (nitf::ExtensionsIterator it = extensions.begin(); + it != extensions.end(); ++it) + { + nitf::TRE tre = *it; + + std::string treID = tre.getID(); + printTRE(tre); + } +} + + +void showFileHeader(nitf::FileHeader header) +{ + SHOW( header.getFileHeader().toString() ); + SHOW( header.getFileVersion().toString() ); + SHOW( header.getComplianceLevel().toString() ); + SHOW( header.getSystemType().toString() ); + SHOW( header.getOriginStationID().toString() ); + SHOW( header.getFileDateTime().toString() ); + SHOW( header.getFileTitle().toString() ); + SHOW( header.getClassification().toString() ); + SHOW( header.getMessageCopyNum().toString() ); + SHOW( header.getMessageNumCopies().toString() ); + SHOW( header.getEncrypted().toString() ); + SHOW( header.getBackgroundColor().toString() ); + SHOW( header.getOriginatorName().toString() ); + SHOW( header.getOriginatorPhone().toString() ); + SHOW( header.getFileLength().toString() ); + SHOW( header.getHeaderLength().toString() ); + + unsigned int num = header.getNumImages(); + std::cout << "The number of images contained in this file [" + << num << "]" << std::endl; + + for (unsigned int i = 0; i < num; i++) + { + nitf::ComponentInfo info = header.getImageInfo(i); + + std::cout << "\tThe length of image subheader [" << i << "]: " + << (unsigned int)info.getLengthSubheader() << std::endl; + } + + num = header.getNumGraphics(); + + std::cout << "The number of graphics contained in this file [" + << num << "]" << std::endl; + + for (unsigned int i = 0; i < num; i++) + { + nitf::ComponentInfo info = header.getGraphicInfo(i); + + std::cout << "\tThe length of graphics subheader [" << i << "]: " + << (unsigned int)info.getLengthSubheader() << std::endl; + + std::cout << "\tThe length of the graphics data: " + << (unsigned int)info.getLengthData() + << "bytes\n" << std::endl; + } + + num = header.getNumLabels(); + + std::cout << "The number of labels contained in this file [" + << num << "]" << std::endl; + + for (unsigned int i = 0; i < num; i++) + { + nitf::ComponentInfo info = header.getLabelInfo(i); + + std::cout << "\tThe length of label subheader [" << i << "]: " + << (unsigned int)info.getLengthSubheader() << std::endl; + + std::cout << "\tThe length of the label data: " + << (unsigned int)info.getLengthData() + << "bytes\n" << std::endl; + } + + num = header.getNumTexts(); + std::cout << "The number of texts contained in this file [" + << num << "]" << std::endl; + + for (unsigned int i = 0; i < num; i++) + { + nitf::ComponentInfo info = header.getTextInfo(i); + std::cout << "\tThe length of text subheader [" << i << "]: " + << (unsigned int)info.getLengthSubheader() << std::endl; + + std::cout << "\tThe length of the text data: " + << (unsigned int)info.getLengthData() + << "bytes\n" << std::endl; + } + + num = header.getNumDataExtensions(); + std::cout << "The number of DES contained in this file [" + << num << "]" << std::endl; + + for (unsigned int i = 0; i < num; i++) + { + nitf::ComponentInfo info = header.getDataExtensionInfo(i); + + std::cout << "\tThe length of DES subheader [" << i << "]: " + << (unsigned int)info.getLengthSubheader() << std::endl; + + std::cout << "\tThe length of the DES data: " + << (unsigned int)info.getLengthData() + << "bytes\n" << std::endl; + } + + num = header.getNumReservedExtensions(); + std::cout << "The number of RES contained in this file [" + << num << "]" << std::endl; + + for (unsigned int i = 0; i < num; i++) + { + nitf::ComponentInfo info = header.getReservedExtensionInfo(i); + std::cout << "\tThe length of RES subheader [" << i << "]: " + << (unsigned int)info.getLengthSubheader() << std::endl; + + std::cout << "\tThe length of the RES data: " + << (unsigned int)info.getLengthData() + << "bytes\n" << std::endl; + } + + SHOW(header.getUserDefinedHeaderLength().toString()); + + nitf::Extensions udExts = header.getUserDefinedSection(); + + showExtensions(udExts); + + SHOW(header.getExtendedHeaderLength().toString()); + + nitf::Extensions exExts = header.getExtendedSection(); + showExtensions(exExts); + +} + + +void showImageSubheader(nitf::ImageSubheader imsub) +{ + unsigned int i; + std::cout << "image subheader" << std::endl; + SHOW( imsub.getFilePartType().toString() ); + SHOW( imsub.getImageId().toString() ); + SHOW( imsub.getImageDateAndTime().toString() ); + SHOW( imsub.getTargetId().toString() ); + SHOW( imsub.getImageTitle().toString() ); + SHOW( imsub.getImageSecurityClass().toString() ); + SHOW( imsub.getEncrypted().toString() ); + SHOW( imsub.getImageSource().toString() ); + SHOW( imsub.getNumRows().toString() ); + SHOW( imsub.getNumCols().toString() ); + SHOW( imsub.getPixelValueType().toString() ); + SHOW( imsub.getImageRepresentation().toString() ); + SHOW( imsub.getImageCategory().toString() ); + SHOW( imsub.getActualBitsPerPixel().toString() ); + SHOW( imsub.getPixelJustification().toString() ); + SHOW( imsub.getImageCoordinateSystem().toString() ); + SHOW( imsub.getCornerCoordinates().toString() ); + + SHOW( (nitf::Uint32)imsub.getNumImageComments() ); + nitf::List comments = imsub.getImageComments(); + for (nitf::ListIterator it = comments.begin(); it != comments.end(); ++it) + SHOW(((nitf::Field)*it).toString()); + + SHOW( imsub.getImageCompression().toString() ); + SHOW( imsub.getCompressionRate().toString() ); + + SHOW( imsub.getNumImageBands().toString() ); + SHOW( (nitf::Uint32)imsub.getNumMultispectralImageBands() ); + + for (i = 0; i < (unsigned int)imsub.getNumImageBands(); i++) + { + SHOW( imsub.getBandInfo(i).getRepresentation().toString()); + SHOW( imsub.getBandInfo(i).getSubcategory().toString() ); + SHOW( imsub.getBandInfo(i).getImageFilterCondition().toString() ); + SHOW( imsub.getBandInfo(i).getImageFilterCode().toString() ); + SHOW( (nitf::Uint32)imsub.getBandInfo(i).getNumLUTs() ); + SHOW( (nitf::Uint32)imsub.getBandInfo(i).getBandEntriesPerLUT() ); + } + + SHOW( imsub.getImageSyncCode().toString() ); + SHOW( imsub.getImageMode().toString() ); + SHOW( (nitf::Uint32)imsub.getNumBlocksPerRow() ); + SHOW( (nitf::Uint32)imsub.getNumBlocksPerCol() ); + SHOW( (nitf::Uint32)imsub.getNumPixelsPerHorizBlock() ); + SHOW( (nitf::Uint32)imsub.getNumPixelsPerVertBlock() ); + SHOW( (nitf::Uint32)imsub.getNumBitsPerPixel() ); + SHOW( imsub.getImageDisplayLevel().toString() ); + SHOW( imsub.getImageAttachmentLevel().toString() ); + SHOW( imsub.getImageLocation().toString() ); + SHOW( imsub.getImageMagnification().toString() ); + SHOW( imsub.getUserDefinedImageDataLength().toString() ); + SHOW( imsub.getUserDefinedOverflow().toString() ); + + //the hash functor + // ShowTREFunctor showTRE; + nitf::Extensions udExts = imsub.getUserDefinedSection(); + showExtensions(udExts); + // nitf::HashTable htUd = udExts.getHash(); + // htUd.foreach(showTRE); + + SHOW( (nitf::Uint32)imsub.getExtendedHeaderLength() ); + SHOW( imsub.getExtendedHeaderOverflow().toString() ); + + nitf::Extensions exExts = imsub.getExtendedSection(); + showExtensions(exExts); + // nitf::HashTable htEx = exExts.getHash(); + // htEx.foreach(showTRE); + +} + + +/* + * This function dumps the security header. + * + */ +void showSecurityGroup(nitf::FileSecurity securityGroup) +{ + SHOW(securityGroup.getClassificationSystem().toString()); + SHOW(securityGroup.getCodewords().toString()); + SHOW(securityGroup.getControlAndHandling().toString()); + SHOW(securityGroup.getReleasingInstructions().toString()); + SHOW(securityGroup.getDeclassificationType().toString()); + SHOW(securityGroup.getDeclassificationDate().toString()); + SHOW(securityGroup.getDeclassificationExemption().toString()); + SHOW(securityGroup.getDowngrade().toString()); + SHOW(securityGroup.getDowngradeDateTime().toString()); + SHOW(securityGroup.getClassificationText().toString()); + SHOW(securityGroup.getClassificationAuthorityType().toString()); + SHOW(securityGroup.getClassificationAuthority().toString()); + SHOW(securityGroup.getClassificationReason().toString()); + SHOW(securityGroup.getSecuritySourceDate().toString()); + SHOW(securityGroup.getSecurityControlNumber().toString()); +} + +/* + * This section is for vector graphics. Currently + * this will be CGM 1.0 (there is a spec for NITF CGM, + * but the original CGM 1.0 spec is out-of-print. + * + * Note that this function does not dump the binary CGM + * You can use the NITRO CGM library to read the CGM data + * from the NITF (and dump it) + */ + +void showGraphicSubheader(nitf::GraphicSubheader sub) +{ + + std::cout << "graphic subheader" << std::endl; + + SHOW(sub.getFilePartType().toString()); + SHOW(sub.getGraphicID().toString()); + SHOW(sub.getName().toString()); + SHOW(sub.getSecurityClass().toString()); + + if (*(sub.getSecurityClass().getRawData()) != 'U') + showSecurityGroup(sub.getSecurityGroup()); + + SHOW(sub.getEncrypted().toString()); + SHOW(sub.getStype().toString()); + SHOW(sub.getRes1().toString()); + SHOW(sub.getDisplayLevel().toString()); + SHOW(sub.getAttachmentLevel().toString()); + SHOW(sub.getLocation().toString()); + SHOW(sub.getBound1Loc().toString()); + SHOW(sub.getColor().toString()); + SHOW(sub.getBound2Loc().toString()); + SHOW(sub.getRes2().toString()); + SHOW(sub.getExtendedHeaderLength().toString()); + SHOW(sub.getExtendedHeaderOverflow().toString()); + + nitf::Extensions exts = sub.getExtendedSection(); + showExtensions(exts); + +} + + +void showLabelSubheader(nitf::LabelSubheader sub) +{ + printf("label subheader"); + + SHOW(sub.getFilePartType().toString()); + SHOW(sub.getLabelID().toString()); + SHOW(sub.getSecurityClass().toString()); + + if (*(sub.getSecurityClass().getRawData()) != 'U') + showSecurityGroup(sub.getSecurityGroup()); + + SHOW(sub.getEncrypted().toString()); + SHOW(sub.getFontStyle().toString()); + SHOW(sub.getCellWidth().toString()); + SHOW(sub.getCellHeight().toString()); + SHOW(sub.getDisplayLevel().toString()); + SHOW(sub.getAttachmentLevel().toString()); + SHOW(sub.getLocationRow().toString()); + SHOW(sub.getLocationColumn().toString()); + SHOWRGB(sub.getTextColor().getRawData()); + SHOWRGB(sub.getBackgroundColor().getRawData()); + SHOW(sub.getExtendedHeaderLength().toString()); + SHOW(sub.getExtendedHeaderOverflow().toString()); + + nitf::Extensions exts = sub.getExtendedSection(); + showExtensions(exts); + +} + +/* + * This section contains raw text data. You can put + * lots of stuff in here but most people never do. + * + * Note that XML data is usually not contained in this section + * even though that might have made more sense. XML data is + * typically found in the DES segment + */ +void showTextSubheader(nitf::TextSubheader sub) +{ + std::cout << "text subheader" << std::endl; + SHOW(sub.getFilePartType().toString()); + SHOW(sub.getTextID().toString()); + SHOW(sub.getAttachmentLevel().toString()); + SHOW(sub.getDateTime().toString()); + SHOW(sub.getTitle().toString()); + SHOW(sub.getSecurityClass().toString()); + + if (*(sub.getSecurityClass().getRawData()) != 'U') + showSecurityGroup(sub.getSecurityGroup()); + + SHOW(sub.getEncrypted().toString()); + SHOW(sub.getFormat().toString()); + SHOW(sub.getExtendedHeaderLength().toString()); + SHOW(sub.getExtendedHeaderOverflow().toString()); + + nitf::Extensions exts = sub.getExtendedSection(); + showExtensions(exts); + + +} + +/* + * This section is for dumping the Data Extension Segment (DES) + * subheader. It can hold up to 1GB worth of data, so its big + * enough for most things. People stuff all kinds of things in + * the DESDATA block including + * + * - TRE overflow: + * When a TRE is too big for the section its in. In other words, + * if populating it properly would overflow the segment, it is + * dumped into the TRE overflow segment. + * + * This is kind of a pain, and so NITRO 2.0 has functions to + * split this up for you, or merge it back into the header where it + * would go if it wasnt too big (see nitf_Record_mergeTREs() and + * nitf_Record_unmergeTREs). + * + * However, by default, we assume that you want the data as it + * appeared in the file. Therefore, when you dump a record, you + * might see overflow data + * + * - Text data (especially XML) + * + * XML data is getting more popular, and to make sure that they + * dont have to worry about the length of the XML surpassing the + * limits of a segment, most people decide to spec. it to go here + * + * - Binary data + * + * Since the DES is the wild west of the NITF, you can put anything + * you want here. + * + * Confusingly, the DES subheader has its own little TRE-like + * arbitrary key-value params. In NITRO we treat this as a TRE within + * the subheader. + * + * This function prints the DE subheader, the extended TRE described above, + * and additionally, if the DESDATA is TRE overflow, we dump those too. + */ +void showDESubheader(nitf::DESubheader sub) +{ + printf("DES subheader\n"); + SHOW(sub.getFilePartType().toString()); + SHOW(sub.getTypeID().toString()); + SHOW(sub.getVersion().toString()); + SHOW(sub.getSecurityClass().toString()); + + if (*(sub.getSecurityClass().getRawData()) != 'U') + showSecurityGroup(sub.getSecurityGroup()); + + SHOW(sub.getOverflowedHeaderType().toString()); + SHOW(sub.getDataItemOverflowed().toString()); + SHOW(sub.getSubheaderFieldsLength().toString()); + + /* + * This is the user defined parameter section + * within the DES. It contains only BCS-A/N type values + * so storing it in a 'TRE' struct is no big deal + * + * It is only valid if the subheader fields length > 0; otherwise, it will + * throw an Exception since there is no TRE defining the subheader fields. + */ + if (((nitf::Uint32)sub.getSubheaderFieldsLength()) > 0) + { + nitf::TRE tre = sub.getSubheaderFields(); + printTRE( tre ); + } + + SHOWI(sub.getDataLength()); + + /* + * NITRO only populates this object if the DESDATA contains + * TRE overflow. Otherwise, you need to use a DEReader to + * get at the DESDATA, since it can contain anything. + * + * We wont bother to try and print whatever other things might + * have been put in here (e.g, text data or binary blobs) + */ + nitf::Extensions exts = sub.getUserDefinedSection(); + showExtensions(exts); +} + + +/* + * This section is never really populated + */ +void showRESubheader(nitf::RESubheader sub) +{ + std::cout << "RES subheader\n" << std::endl; + + SHOW(sub.getFilePartType().toString()); + SHOW(sub.getTypeID().toString()); + SHOW(sub.getVersion().toString()); + SHOW(sub.getSecurityClass().toString()); + + if (*(sub.getSecurityClass().getRawData()) != 'U') + showSecurityGroup(sub.getSecurityGroup()); + + SHOW(sub.getSubheaderFieldsLength().toString()); + + SHOWI(sub.getDataLength()); +} + +int main(int argc, char **argv) +{ + + try + { + // This is the reader object + nitf::Reader reader; + + if ( argc != 2 ) + { + std::cout << "Usage: " << argv[0] << " " << std::endl; + exit(EXIT_FAILURE); + } + + if (nitf::Reader::getNITFVersion( argv[1] ) == NITF_VER_UNKNOWN) + { + std::cout << "This file does not appear to be a valid NITF" + << std::endl; + exit(EXIT_FAILURE); + } + + /* + * Using an IO handle is one valid way to read a NITF in + * + * NITRO 2.5 offers other ways, using the readIO() function + * in the Reader + */ + nitf::IOHandle io(argv[1]); + + // This parses all header data within the NITF + nitf::Record record = reader.read(io); + + // Now show the header + nitf::FileHeader fileHeader = record.getHeader(); + + // Now show the header + showFileHeader(fileHeader); + + // And now show the image information + if (record.getNumImages()) + { + nitf::List images = record.getImages(); + + // Walk each image and show + for (nitf::ListIterator iter = images.begin(); + iter != images.end(); ++iter) + { + nitf::ImageSegment segment = *iter; + showImageSubheader(segment.getSubheader()); + } + } + else + { + std::cout << "No image in file!\n" << std::endl; + } + + // Graphics + if (record.getNumGraphics()) + { + nitf::List graphics = record.getGraphics(); + + // Walk each graphic and show + for (nitf::ListIterator iter = graphics.begin(); + iter != graphics.end(); ++iter) + { + nitf::GraphicSegment segment = *iter; + showGraphicSubheader(segment.getSubheader()); + } + } + else + { + std::cout << "No graphics in file" << std::endl; + } + + // Labels + if (record.getNumLabels()) + { + nitf::List labels = record.getLabels(); + + // Walk each label and show + for (nitf::ListIterator iter = labels.begin(); + iter != labels.end(); ++iter) + { + nitf::LabelSegment segment = *iter; + showLabelSubheader(segment.getSubheader()); + } + } + else + { + std::cout << "No label in file" << std::endl; + } + + // Texts + if (record.getNumTexts()) + { + nitf::List texts = record.getTexts(); + + // Walk each label and show + for (nitf::ListIterator iter = texts.begin(); + iter != texts.end(); ++iter) + { + nitf::TextSegment segment = *iter; + showTextSubheader(segment.getSubheader()); + } + } + else + { + std::cout << "No texts in file" << std::endl; + } + + // Data Extensions + if (record.getNumDataExtensions()) + { + nitf::List des = record.getDataExtensions(); + + // Walk each label and show + for (nitf::ListIterator iter = des.begin(); + iter != des.end(); ++iter) + { + nitf::DESegment segment = *iter; + showDESubheader(segment.getSubheader()); + } + } + else + { + std::cout << "No data extensions in file" << std::endl; + } + + // Data Extensions + if (record.getNumReservedExtensions()) + { + nitf::List res = record.getReservedExtensions(); + + // Walk each label and show + for (nitf::ListIterator iter = res.begin(); + iter != res.end(); ++iter) + { + nitf::RESegment segment = *iter; + showRESubheader(segment.getSubheader()); + } + } + else + { + std::cout << "No reserved extensions in file" << std::endl; + } + + io.close(); + + // Warnings + nitf::List warnings = reader.getWarningList(); + if (!warnings.isEmpty()) + { + // Iterator to a list + nitf::ListIterator iter = warnings.begin(); + + // Iterator to the end of list + nitf::ListIterator end = warnings.end(); + + std::cout << "WARNINGS: "; + std::cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"; + + // While we are not at the end + while (iter != end) + { + //char *p = (char *) nitf_ListIterator_get(&it); + char *p = (char *) * iter; + + // Make sure + assert(p != NULL); + + // Show the data + std::cout << "\tFound problem: [" << p << "]\n" << std::endl; + + ++iter; + } + + std::cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"; + } + return 0; + } + catch (except::Throwable& t) + { + std::cout << t.getTrace() << std::endl; + } +} diff --git a/modules/c++/nitf/build/Makefile.in b/modules/c++/nitf/build/Makefile.in new file mode 100644 index 000000000..77748edc3 --- /dev/null +++ b/modules/c++/nitf/build/Makefile.in @@ -0,0 +1,70 @@ +# ========================================================================= +# This file is part of NITRO +# ========================================================================= +# +# (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems +# +# NITRO is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, If not, +# see . +# + +#---------------------------------------- +# Project specific +#---------------------------------------- +include ../build/project.make + +TARGET = @target@ +LANGUAGE = c++ +#---------------------------------------- +# Compile flags +#---------------------------------------- +CXX = @purify@ @CXX@ +CXXDEFINES = @cxx_defs@ $(MY_CXXDEFINES) +CXXFLAGS = @cxx_flags@ $(MY_CXXFLAGS) +INCLUDES = -I../include @cxx_includes@ $(MY_INCLUDES) +COMPILE = $(CXX) $(CXXFLAGS) $(CXXDEFINES) $(INCLUDES) + +#---------------------------------------- +# Library flags +#---------------------------------------- +ARCHIVE = @AR@ @ar_flags@ +ARCHNAME = $(PACKAGE)-$(LANGUAGE) +LIBNAME = lib$(ARCHNAME).a +LIBDIR = ../lib/$(TARGET)/@lib_dir@ +DSONAME = lib$(ARCHNAME).so +LIBS = -l$(ARCHNAME) $(MY_LIBS) @link_libs@ + +#---------------------------------------- +# Link +#---------------------------------------- +LIBPATH = -L$(LIBDIR) $(MY_LIBPATH) @link_libpath@ +LINK = $(LIBPATH) $(LFLAGS) $(LIBS) +LFLAGS = @link_flags@ $(MY_LFLAGS) +#---------------------------------------- +# DSO flags +#---------------------------------------- +DLLFLAGS = @dll_flags@ +DSODIR = ../plugins/$(TARGET)/@lib_dir@ +DSO = ${PLUGINS:.cpp=.so} + +#---------------------------------------- +# Test flags +#---------------------------------------- +TESTDIR = ../bin/$(TARGET) + +#---------------------------------------- +# Misc. +#---------------------------------------- +DSOEXT = .so +LIBEXT = .a diff --git a/modules/c++/nitf/build/project.make.in b/modules/c++/nitf/build/project.make.in new file mode 100644 index 000000000..7ef85d83f --- /dev/null +++ b/modules/c++/nitf/build/project.make.in @@ -0,0 +1,103 @@ +# ========================================================================= +# This file is part of NITRO +# ========================================================================= +# +# (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems +# +# NITRO is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, If not, +# see . +# + +PACKAGE = nitf +BUILD = library unit-tests +MAJOR_VERSION = 2 +MINOR_VERSION = 7 +VERSION_SUFFIX =dev +VERSION = $(MAJOR_VERSION)_$(MINOR_VERSION)$(VERSION_SUFFIX) +MAINTAINER = gojira_1@users.sourceforge.net, tzellman@users.sourceforge.net +DESCRIPTION = A complete solution for reading and writing NITF \ + files. C++ bindings for the C core library. + +# BufferedReader.cpp +SOURCES = BandInfo.cpp \ + BandSource.cpp \ + BlockingInfo.cpp \ + BufferedWriter.cpp \ + ComponentInfo.cpp \ + DataSource.cpp \ + DateTime.cpp \ + DESegment.cpp \ + DESubheader.cpp \ + DownSampler.cpp \ + FileHeader.cpp \ + FileSecurity.cpp \ + GraphicSegment.cpp \ + GraphicSubheader.cpp \ + Handle.cpp \ + HashTable.cpp \ + ImageReader.cpp \ + ImageSegment.cpp \ + ImageSource.cpp \ + ImageSubheader.cpp \ + ImageWriter.cpp \ + IOInterface.cpp \ + LabelSegment.cpp \ + LabelSubheader.cpp \ + List.cpp \ + LookupTable.cpp \ + PluginRegistry.cpp \ + Reader.cpp \ + Record.cpp \ + RESegment.cpp \ + RESubheader.cpp \ + SegmentReader.cpp \ + SegmentSource.cpp \ + SegmentWriter.cpp \ + SubWindow.cpp \ + TextSegment.cpp \ + TextSubheader.cpp \ + TRE.cpp \ + Utils.cpp \ + WriteHandler.cpp \ + Writer.cpp + + +TESTS = test_buffered_write.cpp \ + test_create.cpp \ + test_des_create.cpp \ + test_fh.cpp \ + test_fhdr_clone.cpp \ + test_file_source.cpp \ + test_hash_table_1.cpp \ + test_image_loading.cpp \ + test_list_1.cpp \ + test_list_2.cpp \ + test_read_acftb.cpp \ + test_tre_mods.cpp \ + test_writer_3.cpp + +APPS = show_nitf++.cpp + +MY_CXXFLAGS = +MY_CXXDEFINES = +MY_LFLAGS = +MY_INCLUDES = -I@top_srcdir@/except/include \ + -I@top_srcdir@/str/include \ + -I@top_srcdir@/sys/include \ + -I@top_srcdir@/mt/include +MY_LIBPATH = -L@top_srcdir@/except/lib/@target@/@lib_dir@ \ + -L@top_srcdir@/str/lib/@target@/@lib_dir@ \ + -L@top_srcdir@/sys/lib/@target@/@lib_dir@ \ + -L@top_srcdir@/mt/lib/@target@/@lib_dir@ +MY_LIBS = -lnitf-c -lnrt-c -lmt-c++ -lsys-c++ -lstr-c++ -lexcept-c++ diff --git a/modules/c++/nitf/include/import/nitf.hpp b/modules/c++/nitf/include/import/nitf.hpp new file mode 100644 index 000000000..557c9c4dd --- /dev/null +++ b/modules/c++/nitf/include/import/nitf.hpp @@ -0,0 +1,79 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __IMPORT_NITF_HPP__ +#define __IMPORT_NITF_HPP__ + +#include "nitf/BandInfo.hpp" +#include "nitf/BandSource.hpp" +#include "nitf/BlockingInfo.hpp" +#include "nitf/BufferedWriter.hpp" +#include "nitf/ComponentInfo.hpp" +#include "nitf/DataSource.hpp" +#include "nitf/DateTime.hpp" +#include "nitf/DESegment.hpp" +#include "nitf/DESubheader.hpp" +#include "nitf/DownSampler.hpp" +#include "nitf/Extensions.hpp" +#include "nitf/Field.hpp" +#include "nitf/FieldWarning.hpp" +#include "nitf/FileHeader.hpp" +#include "nitf/FileSecurity.hpp" +#include "nitf/GraphicSegment.hpp" +#include "nitf/GraphicSubheader.hpp" +#include "nitf/Handle.hpp" +#include "nitf/HandleManager.hpp" +#include "nitf/HashTable.hpp" +#include "nitf/IOInterface.hpp" +#include "nitf/IOHandle.hpp" +#include "nitf/ImageReader.hpp" +#include "nitf/ImageSegment.hpp" +#include "nitf/ImageSource.hpp" +#include "nitf/ImageSubheader.hpp" +#include "nitf/ImageWriter.hpp" +#include "nitf/LabelSegment.hpp" +#include "nitf/LabelSubheader.hpp" +#include "nitf/List.hpp" +#include "nitf/LookupTable.hpp" +#include "nitf/MemoryIO.hpp" +#include "nitf/NITFException.hpp" +#include "nitf/Object.hpp" +#include "nitf/Pair.hpp" +#include "nitf/PluginRegistry.hpp" +#include "nitf/RESegment.hpp" +#include "nitf/RESubheader.hpp" +#include "nitf/Reader.hpp" +#include "nitf/Record.hpp" +#include "nitf/SegmentReader.hpp" +#include "nitf/SegmentSource.hpp" +#include "nitf/SegmentWriter.hpp" +#include "nitf/SubWindow.hpp" +#include "nitf/System.hpp" +#include "nitf/TRE.hpp" +#include "nitf/TextSegment.hpp" +#include "nitf/TextSubheader.hpp" +#include "nitf/Utils.hpp" +#include "nitf/WriteHandler.hpp" +#include "nitf/Writer.hpp" +#include "nitf/WriterOptions.hpp" + +#endif diff --git a/modules/c++/nitf/include/nitf/BandInfo.hpp b/modules/c++/nitf/include/nitf/BandInfo.hpp new file mode 100644 index 000000000..bb255fe4a --- /dev/null +++ b/modules/c++/nitf/include/nitf/BandInfo.hpp @@ -0,0 +1,122 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_BANDINFO_HPP__ +#define __NITF_BANDINFO_HPP__ + +#include "nitf/BandInfo.h" +#include "nitf/System.hpp" +#include "nitf/LookupTable.hpp" +#include "nitf/Field.hpp" +#include "nitf/Object.hpp" +#include + +/*! + * \file BandInfo.hpp + * \brief Contains wrapper implementation for BandInfo + */ + +namespace nitf +{ +/*! + * \class BandInfo + * \brief The C++ wrapper for the nitf_BandInfo + */ +DECLARE_CLASS(BandInfo) +{ +public: + + //! Copy constructor + BandInfo(const BandInfo & x); + + //! Assignment Operator + BandInfo & operator=(const BandInfo & x); + + //! Set native object + BandInfo(nitf_BandInfo * x); + + //! Constructor + BandInfo(); + + //! Destructor + ~BandInfo(); + + //! Get the representation + nitf::Field getRepresentation(); + + //! Get the subcategory + nitf::Field getSubcategory(); + + //! Get the imageFilterCondition + nitf::Field getImageFilterCondition(); + + //! Get the imageFilterCode + nitf::Field getImageFilterCode(); + + //! Get the numLUTs + nitf::Field getNumLUTs(); + + //! Get the bandEntriesPerLUT + nitf::Field getBandEntriesPerLUT(); + + //! Get the LookUpTable associated with this BandInfo + nitf::LookupTable getLookupTable(); + + /*! + * Initialize the BandInfo with the given data + * + * \param representation The band representation + * \param subcategory The band subcategory + * \param imageFilterCondition The band filter condition + * \param imageFilterCode The band standard image filter code + * \param numLUTs The number of look-up tables + * \param bandEntriesPerLUT The number of entries/LUT + * \param lut The look-up tables + */ + void init(const std::string& representation, + const std::string& subcategory, + const std::string& imageFilterCondition, + const std::string& imageFilterCode, + nitf::Uint32 numLUTs, + nitf::Uint32 bandEntriesPerLUT, + nitf::LookupTable& lut) throw(nitf::NITFException); + + /*! + * Initialize the BandInfo with the given data. This assumes there is no + * LUT data. + * + * \param representation The band representation + * \param subcategory The band subcategory + * \param imageFilterCondition The band filter condition + * \param imageFilterCode The band standard image filter code + */ + void init(const std::string& representation, + const std::string& subcategory, + const std::string& imageFilterCondition, + const std::string& imageFilterCode) throw(nitf::NITFException); + +private: + nitf_Error error; +}; + +} +#endif diff --git a/modules/c++/nitf/include/nitf/BandSource.hpp b/modules/c++/nitf/include/nitf/BandSource.hpp new file mode 100644 index 000000000..a8115c85e --- /dev/null +++ b/modules/c++/nitf/include/nitf/BandSource.hpp @@ -0,0 +1,175 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_BANDSOURCE_HPP__ +#define __NITF_BANDSOURCE_HPP__ + +#include "nitf/BandSource.h" +#include "nitf/RowSource.h" +#include "nitf/DirectBlockSource.h" +#include "nitf/DataSource.hpp" +#include "nitf/IOHandle.hpp" +#include "nitf/System.hpp" +#include "nitf/ImageReader.hpp" +#include + +/*! + * \file BandSource.hpp + * \brief Contains wrapper implementations for BandSources + */ +namespace nitf +{ +//! BandSource === DataSource +typedef DataSource BandSource; + +/*! + * \class MemorySource + * \brief The C++ wrapper for the nitf_MemorySource. + * + * The memory source class allows us to read directly from + * a data buffer. In the event that this is a memory-mapped file, + * we will likely get a performance gain over the direct fd approach. + * + * The constructor takes in a buffer, a size, and optionally a + * sampling factor (Typically, the factor will be applied most + * times during the case of memory mapping, although it may be used + * to sample down or cut the image into pieces). + */ +class MemorySource : public BandSource +{ +public: + /*! + * Constructor + * \param data The memory buffer + * \param size The size of the buffer + * \param numBytesPerPixel The number of bytes per pixel + * \param start The start offset + * \param pixelSkip The amount of pixels to skip + */ + MemorySource(char * data, size_t size, nitf::Off start, + int numBytesPerPixel, int pixelSkip) throw (nitf::NITFException); +}; + +/*! + * \class FileSource + * \brief The C++ wrapper for the nitf_FileSource + * + * The FileSource class is a BandSource that comes from an open + * file descriptor or handle. Due to any number of constraints, + * not the least of which is the band interleaved by pixel case, + * we allow the creator to specify a start point, and a pixel skip + * (this would help you create a thumbnail as well). + */ +class FileSource : public BandSource +{ +public: + FileSource(const std::string& fname, + nitf::Off start, + int numBytesPerPixel, + int pixelSkip) throw (nitf::NITFException); + + /*! + * Constructor + * \param handle The handle to store + * \param start The location to seek to (as the beginning) + * \param numBytesPerPixel The number of bytes per pixel + * \param pixelSkip The number of pixels to skip each time + */ + FileSource(nitf::IOHandle& io, + nitf::Off start, + int numBytesPerPixel, + int pixelSkip) throw (nitf::NITFException); +}; + +struct RowSourceCallback +{ + virtual ~RowSourceCallback() + { + } + + virtual void nextRow(nitf::Uint32 band, char* buf) throw (nitf::NITFException) = 0; +}; + +class RowSource : public BandSource +{ +public: + RowSource(nitf::Uint32 band, nitf::Uint32 numRows, nitf::Uint32 numCols, + nitf::Uint32 pixelSize, RowSourceCallback *callback) + throw (nitf::NITFException); + +private: + static + NITF_BOOL nextRow(void* algorithm, + nitf_Uint32 band, + NITF_DATA* buffer, + nitf_Error* error); + +private: + nitf::Uint32 mBand, mNumRows, mNumCols, mPixelSize; +}; + +class DirectBlockSource : public BandSource +{ +public: + DirectBlockSource(nitf::ImageReader& imageReader, + nitf::Uint32 numBands) + throw (nitf::NITFException); + +protected: + virtual void nextBlock(char* buf, + nitf::Uint8* block, + nitf::Uint32 blockNumber, + nitf::Uint64 blockSize) throw (nitf::NITFException) = 0; +private: + static + NITF_BOOL nextBlock(void *algorithm, + char * buf, + nitf_Uint8 * block, + nitf_Uint32 blockNumber, + nitf_Uint64 blockSize, + nitf_Error * error); +}; + +class CopyBlockSource: public ::nitf::DirectBlockSource +{ +public: + CopyBlockSource(nitf::ImageReader& imageReader, nitf::Uint32 numBands) + throw (::nitf::NITFException) : + nitf::DirectBlockSource(imageReader, numBands) + {} + + virtual ~CopyBlockSource(){} + +protected: + virtual void nextBlock(char* buf, + ::nitf::Uint8* block, + ::nitf::Uint32 blockNumber, + ::nitf::Uint64 blockSize) throw (::nitf::NITFException) + { + memcpy(buf, block, blockSize); + } +}; + + +} + +#endif diff --git a/modules/c++/nitf/include/nitf/BlockingInfo.hpp b/modules/c++/nitf/include/nitf/BlockingInfo.hpp new file mode 100644 index 000000000..9a9e675ff --- /dev/null +++ b/modules/c++/nitf/include/nitf/BlockingInfo.hpp @@ -0,0 +1,109 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_BLOCKING_INFO_HPP__ +#define __NITF_BLOCKING_INFO_HPP__ + +#include "nitf/System.hpp" +#include "nitf/IOInterface.hpp" +#include "nitf/ImageIO.h" +#include "nitf/ImageSubheader.hpp" +#include "nitf/SubWindow.hpp" +#include "nitf/Object.hpp" +#include + +/*! + * \file BlockingInfo.hpp + * \brief Contains wrapper implementation for BlockingInfo + */ + +namespace nitf +{ + +/*! + * \class BlockingInfo + * \brief The C++ wrapper of the nitf_BlockingInfo + * + * BlockingInfo provides information about an image segment's block + * organization. This structure is obtained by calling the function + * ImageReader::getBlockingInfo(). The information in this structure + * reflects the correct information. Due to the implementation of + * some compression types, the information in the image segment + * header may not be correct. + */ +DECLARE_CLASS(BlockingInfo) +{ +public: + //! Copy constructor + BlockingInfo(const BlockingInfo & x); + + //! Assignment operator + BlockingInfo & operator=(const BlockingInfo & x); + + //! Set native object + BlockingInfo(nitf_BlockingInfo * x); + + //! Constructor + BlockingInfo(); + + //! Destructor + ~BlockingInfo(); + + //! Get the number of blocks per row + nitf::Uint32 getNumBlocksPerRow() const; + + //! Set the number of blocks per row + void setNumBlocksPerRow(nitf::Uint32 value); + + //! Get the number of blocks per column + nitf::Uint32 getNumBlocksPerCol() const; + + //! Set the number of blocks per column + void setNumBlocksPerCol(nitf::Uint32 value); + + //! Get the number of rows per block + nitf::Uint32 getNumRowsPerBlock() const; + + //! Set the number of rows per block + void setNumRowsPerBlock(nitf::Uint32 value); + + //! Get the number of columns per block + nitf::Uint32 getNumColsPerBlock() const; + + //! Set the number of columns per block + void setNumColsPerBlock(nitf::Uint32 value); + + //! Get the length + size_t getLength() const; + + //! Set the length + void setLength(size_t value); + + //! Print the blocking into to file + void print(FILE *file); + +private: + nitf_Error error; +}; + +} +#endif diff --git a/modules/c++/nitf/include/nitf/BufferedWriter.hpp b/modules/c++/nitf/include/nitf/BufferedWriter.hpp new file mode 100644 index 000000000..382a76e18 --- /dev/null +++ b/modules/c++/nitf/include/nitf/BufferedWriter.hpp @@ -0,0 +1,104 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_BUFFERED_WRITER_HPP__ +#define __NITF_BUFFERED_WRITER_HPP__ + +#include +#include +#include + +namespace nitf +{ +class BufferedWriter : public CustomIO +{ +public: + BufferedWriter(const std::string& file, size_t bufferSize); + + BufferedWriter(const std::string& file, + char* buffer, + size_t size, + bool adopt = false); + + virtual ~BufferedWriter(); + + void flushBuffer(); + + nitf::Uint64 getTotalWritten() const + { + return mTotalWritten; + } + + nitf::Uint64 getNumBlocksWritten() const + { + return mBlocksWritten; + } + + nitf::Uint64 getNumPartialBlocksWritten() const + { + return mPartialBlocks; + } + + //! Time spent writing to disk in seconds + double getTotalWriteTime() + { + return mElapsedTime; + } + +protected: + + virtual void readImpl(char* buf, size_t size); + + virtual void writeImpl(const char* buf, size_t size); + + virtual bool canSeekImpl() const; + + virtual nitf::Off seekImpl(nitf::Off offset, int whence); + + virtual nitf::Off tellImpl() const; + + virtual nitf::Off getSizeImpl() const; + + virtual int getModeImpl() const; + + virtual void closeImpl(); + +private: + const size_t mBufferSize; + const mem::ScopedArray mScopedBuffer; + char* const mBuffer; + + nitf::Uint64 mPosition; + nitf::Uint64 mTotalWritten; + nitf::Uint64 mBlocksWritten; + nitf::Uint64 mPartialBlocks; + double mElapsedTime; + + // NOTE: This is at the end to give us a chance to adopt the buffer + // in ScopedArray in case sys::File's constructor throws + mutable sys::File mFile; + + void flushBuffer(const char* buf); +}; + +} +#endif diff --git a/modules/c++/nitf/include/nitf/ComponentInfo.hpp b/modules/c++/nitf/include/nitf/ComponentInfo.hpp new file mode 100644 index 000000000..201d27720 --- /dev/null +++ b/modules/c++/nitf/include/nitf/ComponentInfo.hpp @@ -0,0 +1,89 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_COMPONENTINFO_HPP__ +#define __NITF_COMPONENTINFO_HPP__ + +#include "nitf/ComponentInfo.h" +#include "nitf/System.hpp" +#include "nitf/Field.hpp" +#include "nitf/Object.hpp" +#include + +/*! + * \file ComponentInfo.hpp + * \brief Contains wrapper implementation for ComponentInfo + */ + +namespace nitf +{ + +/*! + * \class ComponentInfo + * \brief The C++ wrapper for the nitf_ComponentInfo + * + * Carries information about the images, graphics, text, or extension + * components contained within the file. + * + * The fields from this class are described in the file header. + * They contain information about some component section + * contained in a NITF file. + */ +DECLARE_CLASS(ComponentInfo) +{ +public: + + //! Copy constructor + ComponentInfo(const ComponentInfo & x); + + //! Assignment Operator + ComponentInfo & operator=(const ComponentInfo & x); + + //! Set native object + ComponentInfo(nitf_ComponentInfo * x); + + //! Clone + nitf::ComponentInfo clone() throw(nitf::NITFException); + + ~ComponentInfo(); + + //! Get the lengthSubheader + nitf::Field getLengthSubheader(); + + //! Get the lengthData + nitf::Field getLengthData(); + +protected: + /*! + * Constructor + * \param subHeaderSize The size of the subheader + * \param dataSize The size of the data + */ + ComponentInfo(nitf::Uint32 subHeaderSize = 0, nitf::Uint64 dataSize = 0) + throw(nitf::NITFException); + +private: + nitf_Error error; +}; + +} +#endif diff --git a/modules/c++/nitf/include/nitf/CompressionInterface.hpp b/modules/c++/nitf/include/nitf/CompressionInterface.hpp new file mode 100644 index 000000000..da9a46207 --- /dev/null +++ b/modules/c++/nitf/include/nitf/CompressionInterface.hpp @@ -0,0 +1,140 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_COMPRESSION_INTERFACE_HPP__ +#define __NITF_COMPRESSION_INTERFACE_HPP__ + +#include +#include +#include + + +/*! + * This is a macro for quickly exposing hooks to a c++ layer + * Compressor object. The idea here is to setup everything in + * one shot. All the user has to do is create a + * nitf_CompressionInterface 'open' method, and declare the + * identifier for compression type. + */ +#define NITF_CREATE_CUSTOM_COMPRESSION(_COMPRESSION_ID, \ + _COMPRESSION_DLL_NAME, \ + _COMPRESSION_ADAPTER_OPEN_FUNC) \ +NITF_CXX_GUARD \ +static const char* _COMPRESSION_ID##_ident[] = \ +{\ + NITF_PLUGIN_COMPRESSION_KEY, #_COMPRESSION_ID, NULL\ +};\ +\ +static nitf_CompressionInterface _COMPRESSION_ID##_INTERFACE_TABLE = {\ + &_COMPRESSION_ADAPTER_OPEN_FUNC,\ + &nitf::CompressionInterface::adapterStart,\ + &nitf::CompressionInterface::adapterWriteBlock,\ + &nitf::CompressionInterface::adapterEnd,\ + &nitf::CompressionInterface::adapterDestroy};\ +\ +NITFAPI(const char**) _COMPRESSION_DLL_NAME##_init(nitf_Error *error)\ +{\ + return _COMPRESSION_ID##_ident;\ +}\ +\ +NITFAPI(void) _COMPRESSION_ID##_cleanup(void)\ +{\ +}\ +\ +NITFAPI(void*) _COMPRESSION_ID##_construct(char* compressionType,\ + nitf_Error* error)\ +{\ + if (strcmp(compressionType, #_COMPRESSION_ID) != 0)\ + {\ + nitf_Error_init(error,\ + "Unsupported compression type",\ + NITF_CTXT,\ + NITF_ERR_COMPRESSION);\ + return NULL;\ + }\ + return &_COMPRESSION_ID##_INTERFACE_TABLE;\ +}\ +NITF_CXX_ENDGUARD + +namespace nitf +{ + +/*! + * \class CompressionInterface + * \brief Compression object controls all innerworkings + * during compression, and gives a c++ api for getting + * things done. + */ +class CompressionInterface +{ +public: + + //! These are canned methods which turn around + // and call the nitf_CompressionControl of your choice + static NITF_BOOL adapterStart(nitf_CompressionControl* object, + nitf::Uint64 offset, + nitf::Uint64 dataLength, + nitf::Uint64* blockMask, + nitf::Uint64* padMask, + nitf_Error* error); + + static NITF_BOOL adapterWriteBlock(nitf_CompressionControl* object, + nitf_IOInterface* io, + const nitf_Uint8* data, + NITF_BOOL pad, + NITF_BOOL noData, + nitf_Error* error); + + static NITF_BOOL adapterEnd(nitf_CompressionControl* object, + nitf_IOInterface* io, + nitf_Error* error); + + static void adapterDestroy(nitf_CompressionControl** object); + +}; + +/*! + * \class Compressor + * \brief This is the c++ interface for nitf_CompressionControl + */ +class Compressor +{ +public: + Compressor() {} + virtual ~Compressor() {} + + virtual void start(nitf::Uint64 offset, + nitf::Uint64 dataLength, + nitf::Uint64* blockMask, + nitf::Uint64* padMask) = 0; + + virtual void writeBlock(nitf::IOInterface& io, + const nitf::Uint8* data, + bool pad, + bool noData) = 0; + + virtual void end(nitf::IOInterface& io) = 0; +}; + +} + +#endif diff --git a/modules/c++/nitf/include/nitf/CustomIO.hpp b/modules/c++/nitf/include/nitf/CustomIO.hpp new file mode 100644 index 000000000..0b2aafdf8 --- /dev/null +++ b/modules/c++/nitf/include/nitf/CustomIO.hpp @@ -0,0 +1,87 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_CUSTOM_IO_HPP__ +#define __NITF_CUSTOM_IO_HPP__ + +#include + +namespace nitf +{ +class CustomIO : public IOInterface +{ +public: + CustomIO(); + + virtual ~CustomIO(); + +protected: + virtual void readImpl(char* buf, size_t size) = 0; + + virtual void writeImpl(const char* buf, size_t size) = 0; + + virtual bool canSeekImpl() const = 0; + + virtual nitf::Off seekImpl(nitf::Off offset, int whence) = 0; + + virtual nitf::Off tellImpl() const = 0; + + virtual nitf::Off getSizeImpl() const = 0; + + virtual int getModeImpl() const = 0; + + virtual void closeImpl() = 0; + +private: + static + nitf_IOInterface* createInterface(CustomIO* me); + + static + NRT_BOOL adapterRead(NRT_DATA* data, char* buf, size_t size, nrt_Error* error); + + static + NRT_BOOL adapterWrite(NRT_DATA* data, const char* buf, size_t size, nrt_Error* error); + + static + NRT_BOOL adapterCanSeek(NRT_DATA* data, nrt_Error* error); + + static + nrt_Off adapterSeek(NRT_DATA* data, nrt_Off offset, int whence, nrt_Error* error); + + static + nrt_Off adapterTell(NRT_DATA* data, nrt_Error* error); + + static + nrt_Off adapterGetSize(NRT_DATA* data, nrt_Error* error); + + static + int adapterGetMode(NRT_DATA* data, nrt_Error* error); + + static + NRT_BOOL adapterClose(NRT_DATA* data, nrt_Error* error); + + static + void adapterDestruct(NRT_DATA* data); +}; +} + +#endif diff --git a/modules/c++/nitf/include/nitf/DESegment.hpp b/modules/c++/nitf/include/nitf/DESegment.hpp new file mode 100644 index 000000000..082d2e5ff --- /dev/null +++ b/modules/c++/nitf/include/nitf/DESegment.hpp @@ -0,0 +1,94 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_DESEGMENT_HPP__ +#define __NITF_DESEGMENT_HPP__ + +#include "nitf/DESegment.h" +#include "nitf/System.hpp" +#include "nitf/NITFException.hpp" +#include "nitf/DESubheader.hpp" +#include "nitf/Object.hpp" +#include + +/*! + * \file DESegment.hpp + * \brief Contains wrapper implementation for DESegment + */ + +namespace nitf +{ + +/*! + * \class DESegment + * \brief The C++ wrapper for the nitf_DESegment + * + * Contains sub-objects that make up a DES. + */ +DECLARE_CLASS(DESegment) +{ +public: + //! Copy constructor + DESegment(const DESegment & x); + + //! Assignment Operator + DESegment & operator=(const DESegment & x); + + //! Set native object + DESegment(nitf_DESegment * x); + + //! Constructor + DESegment() throw(nitf::NITFException); + + DESegment(NITF_DATA * x); + + DESegment & operator=(NITF_DATA * x); + + //! Clone + nitf::DESegment clone() throw(nitf::NITFException); + + ~DESegment(); + + //! Get the subheader + nitf::DESubheader getSubheader(); + + //! Set the subheader + void setSubheader(nitf::DESubheader & value); + + //! Get the offset + nitf::Uint64 getOffset() const; + + //! Set the offset + void setOffset(nitf::Uint64 value); + + //! Get the end + nitf::Uint64 getEnd() const; + + //! Set the end + void setEnd(nitf::Uint64 value); + +private: + nitf_Error error; +}; + +} +#endif diff --git a/modules/c++/nitf/include/nitf/DESubheader.hpp b/modules/c++/nitf/include/nitf/DESubheader.hpp new file mode 100644 index 000000000..57ede5e65 --- /dev/null +++ b/modules/c++/nitf/include/nitf/DESubheader.hpp @@ -0,0 +1,117 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_DESUBHEADER_HPP__ +#define __NITF_DESUBHEADER_HPP__ + +#include "nitf/DESubheader.h" +#include "nitf/Object.hpp" +#include "nitf/Field.hpp" +#include "nitf/FileSecurity.hpp" +#include "nitf/Extensions.hpp" +#include "nitf/TRE.hpp" +#include + +/*! + * \file DESubheader.hpp + * \brief Contains wrapper implementation for DESubheader + */ + +namespace nitf +{ + +/*! + * \class DESubheader + * \brief The C++ wrapper for the nitf_DESubheader + */ +DECLARE_CLASS(DESubheader) +{ +public: + + //! Copy constructor + DESubheader(const DESubheader & x); + + //! Assignment Operator + DESubheader & operator=(const DESubheader & x); + + //! Set native object + DESubheader(nitf_DESubheader * x); + + //! Constructor + DESubheader() throw(nitf::NITFException); + + //! Clone + nitf::DESubheader clone() throw(nitf::NITFException); + + ~DESubheader(); + + //! Get the filePartType + nitf::Field getFilePartType(); + + //! Get the typeID + nitf::Field getTypeID(); + + //! Get the version + nitf::Field getVersion(); + + //! Get the securityClass + nitf::Field getSecurityClass(); + + //! Get the securityGroup + nitf::FileSecurity getSecurityGroup(); + + //! Set the securityGroup + void setSecurityGroup(nitf::FileSecurity value); + + //! Get the overflowedHeaderType + nitf::Field getOverflowedHeaderType(); + + //! Get the dataItemOverflowed + nitf::Field getDataItemOverflowed(); + + //! Get the subheaderFieldsLength + nitf::Field getSubheaderFieldsLength(); + + //! Get the subheaderFields + nitf::TRE getSubheaderFields(); + + //! Set the subheaderFields + void setSubheaderFields(nitf::TRE fields); + + //! Get the dataLength + nitf::Uint32 getDataLength() const; + + //! Set the dataLength + void setDataLength(nitf::Uint32 value); + + //! Get the userDefinedSection + nitf::Extensions getUserDefinedSection(); + + //! Set the userDefinedSection + void setUserDefinedSection(nitf::Extensions value); + +private: + nitf_Error error; +}; + +} +#endif diff --git a/modules/c++/nitf/include/nitf/DataSource.hpp b/modules/c++/nitf/include/nitf/DataSource.hpp new file mode 100644 index 000000000..02587bd95 --- /dev/null +++ b/modules/c++/nitf/include/nitf/DataSource.hpp @@ -0,0 +1,101 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_DATASOURCE_HPP__ +#define __NITF_DATASOURCE_HPP__ + +#include "nitf/DataSource.h" +#include "nitf/System.hpp" +#include "nitf/Object.hpp" +#include + +/*! + * \file DataSource.hpp + * \brief Contains wrapper implementations for DataSources + */ +namespace nitf +{ + +/*! + * \class DataSource + * \brief The C++ wrapper for the nitf_DataSource + */ +DECLARE_CLASS(DataSource) +{ +public: + //! Copy constructor + DataSource(const DataSource & x) + { + setNative(x.getNative()); + } + + //! Assignment Operator + DataSource & operator=(const DataSource & x) + { + if (&x != this) + setNative(x.getNative()); + return *this; + } + + // Set native object + DataSource(nitf_DataSource * x) + { + setNative(x); + getNativeOrThrow(); + } + + DataSource() + { + } + + //! Destructor + virtual ~DataSource() + { + } + + // NOTE: The methods below are used just for testing - the underlying C + // function pointers are what need to be modified if you want to + // have your own source behavior. If you want your own behavior + // for reads, use a RowSource and provide an appropriate + // RowSourceCallback. + + /*! + * Read from the DataSource into the buffer + * \param buf The buffer + * \param size The size of the buffer + */ + void read(char * buf, nitf::Off size) throw (nitf::NITFException); + + /* + * Returns the size of the DataSource, in bytes + */ + nitf::Off getSize(); + + void setSize(nitf::Off size); + +protected: + nitf_Error error; +}; + +} + +#endif diff --git a/modules/c++/nitf/include/nitf/DateTime.hpp b/modules/c++/nitf/include/nitf/DateTime.hpp new file mode 100644 index 000000000..ec412e1b6 --- /dev/null +++ b/modules/c++/nitf/include/nitf/DateTime.hpp @@ -0,0 +1,137 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_DATETIME_HPP__ +#define __NITF_DATETIME_HPP__ + +#include "nitf/System.hpp" +#include "nitf/NITFException.hpp" + +/*! + * \file DateTime.hpp + * \brief Contains wrapper implementation for DateTime (UTC) + */ + +namespace nitf +{ + +/*! + * \class DateTime + * \brief The C++ wrapper for the nitf_DateTime object + * Note that, unlike most of the C++ bindings, this is a deep copy + */ +class DateTime +{ +public: + //! Sets to current date/time + DateTime() throw(nitf::NITFException); + + //! Set native object - takes ownership + DateTime(nitf_DateTime* dateTime) throw(nitf::NITFException); + + DateTime(double timeInMillis) throw(nitf::NITFException); + + DateTime(const std::string& dateString, + const std::string& dateFormat) throw(nitf::NITFException); + + ~DateTime(); + + //! Copy constructor + DateTime(const DateTime& rhs); + + //! Assignment Operator + DateTime & operator=(const DateTime& rhs); + + bool operator<(const DateTime& rhs) const + { + return (mDateTime->timeInMillis < rhs.mDateTime->timeInMillis); + } + + bool operator<=(const DateTime& rhs) const + { + return (mDateTime->timeInMillis <= rhs.mDateTime->timeInMillis); + } + + bool operator>(const DateTime& rhs) const + { + return (mDateTime->timeInMillis > rhs.mDateTime->timeInMillis); + } + + bool operator>=(const DateTime& rhs) const + { + return (mDateTime->timeInMillis >= rhs.mDateTime->timeInMillis); + } + + bool operator==(const DateTime& rhs) const + { + return (mDateTime->timeInMillis == rhs.mDateTime->timeInMillis); + } + + bool operator!=(const DateTime& rhs) const + { + return (mDateTime->timeInMillis != rhs.mDateTime->timeInMillis); + } + + nitf_DateTime* getNative() + { + return mDateTime; + } + + const nitf_DateTime* getNative() const + { + return mDateTime; + } + + void format(const std::string& format, + char* outBuf, + size_t maxSize) const throw(nitf::NITFException); + + void format(const std::string& format, + std::string &str) const throw(nitf::NITFException); + + std::string format(const std::string& format) const + throw(nitf::NITFException); + + int getYear() const; + int getMonth() const; + int getDayOfMonth() const; + int getDayOfWeek() const; + int getDayOfYear() const; + int getHour() const; + int getMinute() const; + double getSecond() const; + double getTimeInMillis() const; + + void setYear(int year); + void setMonth(int month); + void setDayOfMonth(int dayOfMonth); + void setHour(int hour); + void setMinute(int minute); + void setSecond(double second); + void setTimeInMillis(double timeInMillis); + +private: + nitf_DateTime* mDateTime; +}; + +} +#endif diff --git a/modules/c++/nitf/include/nitf/DecompressionInterface.hpp b/modules/c++/nitf/include/nitf/DecompressionInterface.hpp new file mode 100644 index 000000000..b6f3b8df6 --- /dev/null +++ b/modules/c++/nitf/include/nitf/DecompressionInterface.hpp @@ -0,0 +1,139 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_DECOMPRESSION_INTERFACE_HPP__ +#define __NITF_DECOMPRESSION_INTERFACE_HPP__ + +#include +#include +#include +#include + + +/*! + * This is a macro for quickly exposing hooks to a c++ layer + * Decompressor object. The idea here is to setup everything in + * one shot. All the user has to do is create a + * nitf_DecompressionInterface 'open' method, and declare the + * identifier for decompression type. + */ +#define NITF_CREATE_CUSTOM_DECOMPRESSION(_DECOMPRESSION_ID, \ + _DECOMPRESSION_DLL_NAME, \ + _DECOMPRESSION_ADAPTER_OPEN_FUNC) \ +NITF_CXX_GUARD \ +static const char* _DECOMPRESSION_ID##_ident[] = \ +{\ + NITF_PLUGIN_DECOMPRESSION_KEY, #_DECOMPRESSION_ID, NULL\ +};\ +\ +static nitf_DecompressionInterface _DECOMPRESSION_ID##_INTERFACE_TABLE = {\ + &_DECOMPRESSION_ADAPTER_OPEN_FUNC,\ + &nitf::DecompressionInterface::adapterStart,\ + &nitf::DecompressionInterface::adapterReadBlock,\ + &nitf::DecompressionInterface::adapterFreeBlock,\ + &nitf::DecompressionInterface::adapterDestroy};\ +\ +NITFAPI(const char**) _DECOMPRESSION_DLL_NAME##_init(nitf_Error *error)\ +{\ + return _DECOMPRESSION_ID##_ident;\ +}\ +\ +NITFAPI(void) _DECOMPRESSION_ID##_cleanup(void)\ +{\ +}\ +\ +NITFAPI(void*) _DECOMPRESSION_ID##_construct(char* decompressionType,\ + nitf_Error* error)\ +{\ + if (strcmp(decompressionType, #_DECOMPRESSION_ID) != 0)\ + {\ + nitf_Error_init(error,\ + "Unsupported decompression type",\ + NITF_CTXT,\ + NITF_ERR_DECOMPRESSION);\ + return NULL;\ + }\ + return &_DECOMPRESSION_ID##_INTERFACE_TABLE;\ +}\ +NITF_CXX_ENDGUARD + +namespace nitf +{ + +/*! + * \class DecompressionInterface + * \brief Decompression object controls all innerworkings + * during decompression, and gives a c++ api for getting + * things done. + */ +class DecompressionInterface +{ +public: + + //! These are canned methods which turn around + // and call the nitf_DecompressionControl of your choice + static NITF_BOOL adapterStart(nitf_DecompressionControl* object, + nitf_IOInterface* io, + nitf_Uint64 offset, + nitf_Uint64 fileLength, + nitf_BlockingInfo* blockingDefinition, + nitf_Uint64* blockMask, + nitf_Error* error); + + static nitf_Uint8* adapterReadBlock(nitf_DecompressionControl* object, + nitf_Uint32 blockNumber, + nitf_Uint64* blockSize, + nitf_Error* error); + + static NITF_BOOL adapterFreeBlock(nitf_DecompressionControl* object, + nitf_Uint8* block, + nitf_Error* error); + + static void adapterDestroy(nitf_DecompressionControl** object); + +}; + +/*! + * \class Compressor + * \brief This is the c++ interface for nitf_CompressionControl + */ +class Decompressor +{ +public: + Decompressor() {} + virtual ~Decompressor() {} + + virtual void start(nitf::IOInterface& io, + nitf::Uint64 offset, + nitf::Uint64 fileLength, + nitf::BlockingInfo& blockingDefinition, + nitf::Uint64* blockMask) = 0; + + virtual nitf_Uint8* readBlock(nitf::Uint32 blockNumber, + nitf::Uint64* blockSize) = 0; + + virtual void freeBlock(nitf::Uint8* block) = 0; +}; + +} + +#endif diff --git a/modules/c++/nitf/include/nitf/DownSampler.hpp b/modules/c++/nitf/include/nitf/DownSampler.hpp new file mode 100644 index 000000000..0ba826100 --- /dev/null +++ b/modules/c++/nitf/include/nitf/DownSampler.hpp @@ -0,0 +1,231 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_DOWN_SAMPLER_HPP__ +#define __NITF_DOWN_SAMPLER_HPP__ + +#include "nitf/DownSampler.h" +#include "nitf/IOInterface.hpp" +#include "nitf/System.hpp" +#include "nitf/Object.hpp" +#include + +/*! + * \file DownSampler.hpp + * \brief Contains wrapper implementations for DownSamplers + */ + +namespace nitf +{ + +/*! + * \class DownSampler + * \brief The C++ wrapper for the nitf_DownSampler + */ +DECLARE_CLASS(DownSampler) +{ +public: + //! Copy constructor + DownSampler(const DownSampler & x) + { + setNative(x.getNative()); + } + + //! Assignment Operator + DownSampler & operator=(const DownSampler & x) + { + if (&x != this) + setNative(x.getNative()); + return *this; + } + + //! Set native object + DownSampler(nitf_DownSampler * x) + { + setNative(x); + getNativeOrThrow(); + } + + virtual ~DownSampler(){} + + /*! + * Applies a sampling method while reading. + * \param inputWindow The input image fragment + * \param outputWindow A sub-sampled image fragment + * \param numWindowRows How many rows for the input window + * \param numWindowCols How many cols for the input window + * \param numInputCols Number of columns in input buffer, full res + * \param numSubWindowCols The number of columns in the sub-window + * \param pixelType The pixel type (valid values found in System layer) + * \param pixelSize The size of one pixel + * \param rowsInLastWindow The number of rows in the final window + * \param colsInLastWindow The number of cols in the final window + * + * Note: + * The numWindowRows, numWindowCols, and numSubWindowCols values + * are in output image units (units of sample windows). For example, + * with a pixel skip of 3 in columns, if the sub-window request spans + * columns 0-299, then numSubWindowCols is 100. If the block is + * such that a particular request spans columns 90-149 (60 full + * resolution columns), then numWindowCols is 20. The numInputCols + * value is in full resolution units. This value gives the length, + * in pixels, of one row in the input buffer. This buffer is used + * for all down sample calls. Since the number of windows can vary + * from call to call, this buffer has a worst case length. Therefore, + * it is not possible to move from one row to the next with just the + * number of sample windows per row (numWindowCols) for the current + * request. + */ + virtual void apply(NITF_DATA ** inputWindow, + NITF_DATA ** outputWindow, + nitf::Uint32 numBands, + nitf::Uint32 numWindowRows, + nitf::Uint32 numWindowCols, + nitf::Uint32 numInputCols, + nitf::Uint32 numSubWindowCols, + nitf::Uint32 pixelType, + nitf::Uint32 pixelSize, + nitf::Uint32 rowsInLastWindow, + nitf::Uint32 colsInLastWindow) throw (nitf::NITFException); + + nitf::Uint32 getRowSkip(); + + nitf::Uint32 getColSkip(); + +protected: + + DownSampler(){} + nitf_Error error; +}; + + +/*! + * \class PixelSkip + * \brief This class represents a down sample method that + * has a designated skip value in the row and column, + * and it skips the data in between. + * + * The row and column skip factors divide the sub-window + * into non-overlapping sample windows. The upper left + * corner pixel of each sample window is the down sampled + * value for that window. + * + * For a more comprehensive discussion of the merits and + * drawbacks of this type of down sampling, please refer to + * the NITF manual. + */ +class PixelSkip : public DownSampler +{ +public: + /*! + * Constructor + * \param rowSkip The number of rows to skip + * \param colSkip The number of columns to skip + */ + PixelSkip(nitf::Uint32 rowSkip, + nitf::Uint32 colSkip) throw (nitf::NITFException); + + //! Destructor + ~PixelSkip(); +}; + +/*! + * \class MaxDownSample + * \brief Selects the maximum pixel. + * + * The row and column skip factors divide the sub-window + * into non-overlapping sample windows. The pixel with the + * maximum value in each sample window is the down sampled + * value for that window. For complex images, the maximum + * absolute value (the corresponding complex value, not the + * real absolute value) is the down sample value. + * + * For a more comprehensive discussion of the merits and drawbacks + * of this type of down sampling, please refer to the NITF manual. + * + */ +class MaxDownSample : public DownSampler +{ +public: + /*! + * Constructor + * \param rowSkip The number of rows to skip + * \param colSkip The number of columns to skip + */ + MaxDownSample(nitf::Uint32 rowSkip, + nitf::Uint32 colSkip) throw (nitf::NITFException); + //! Destructor + ~MaxDownSample(); +}; + +/*! + * \class SumSq2DownSample + * \brief Sum of square, two band, down-sample method + * + * The maximum is calculated as the sum of the sum of squares of + * two bands. The caller must supply exactly two bands. The + * complex pixel type as the individual band pixel type is + * not supported. + * + * For a more comprehensive discussion of the merits and drawbacks + * of this type of down-sampling, please refer to the NITF manual. + */ +class SumSq2DownSample : public DownSampler +{ +public: + /*! + * Constructor + * \param rowSkip The number of rows to skip + * \param colSkip The number of cols to skip + */ + SumSq2DownSample(nitf::Uint32 rowSkip, + nitf::Uint32 colSkip) throw (nitf::NITFException); + //! Destructor + ~SumSq2DownSample(); +}; + +/*! + * \class Select2DownSample + * \brief First band select, two band, down-sample method + * + * The maximum is calculated as the value of the first band. + * The caller must supply exactly two bands. The complex + * pixel type as the individual band pixel type is not supported. + * + * For a more comprehensive discussion of the merits and drawbacks + * of this type of down-sampling, please refer to the NITF manual. + */ +class Select2DownSample : public DownSampler +{ +public: + /*! + * Constructor + * \param rowSkip The number of rows to skip + * \param colSkip The number of cols to skip + */ + Select2DownSample(nitf::Uint32 rowSkip, + nitf::Uint32 colSkip) throw (nitf::NITFException); + //! Destructor + ~Select2DownSample(); +}; +} +#endif diff --git a/modules/c++/nitf/include/nitf/Extensions.hpp b/modules/c++/nitf/include/nitf/Extensions.hpp new file mode 100644 index 000000000..6283d0087 --- /dev/null +++ b/modules/c++/nitf/include/nitf/Extensions.hpp @@ -0,0 +1,330 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_EXTENSIONS_HPP__ +#define __NITF_EXTENSIONS_HPP__ + +#include "nitf/Extensions.h" +#include "nitf/System.hpp" +#include "nitf/NITFException.hpp" +#include "nitf/TRE.hpp" +#include "nitf/Object.hpp" +#include + +/*! + * \file Extensions.hpp + * \brief Contains wrapper implementation for Extensions + */ + +namespace nitf +{ +/*! + * \class ExtensionsIterator + * \brief The C++ wrapper for the nitf_ExtensionsIterator + */ +class ExtensionsIterator +{ +public: + //! Constructor + ExtensionsIterator(){} + + //! Destructor + ~ExtensionsIterator(){} + + //! Copy constructor + ExtensionsIterator(const ExtensionsIterator & x) + { + handle = x.handle; + } + + //! Assignment Operator + ExtensionsIterator & operator=(const ExtensionsIterator & x) + { + if (&x != this) + handle = x.handle; + return *this; + } + + /*! + * Set native object + */ + ExtensionsIterator(nitf_ExtensionsIterator x) + { + setHandle(x); + } + + /*! + * Get native object + */ + nitf_ExtensionsIterator & getHandle() + { + return handle; + } + + /*! + * Set native object + */ + void setHandle(nitf_ExtensionsIterator x) + { + handle = x; + } + + /*! + * Checks to see if this iterator is equal to another + * \param it2 The iterator to compare with + * \return True if so, and False otherwise + */ + bool equals(nitf::ExtensionsIterator & it2) + { + NITF_BOOL x = nitf_ExtensionsIterator_equals(&handle, &it2.getHandle()); + if (!x) return false; + return true; + } + + bool operator==(const nitf::ExtensionsIterator& it2) + { + return this->equals((nitf::ExtensionsIterator&)it2); + } + + /*! + * Checks to see if this iterator is not equal to another + * \param it2 The iterator to compare with + * \return True if so, and False otherwise + */ + bool notEqualTo(nitf::ExtensionsIterator & it2) + { + NITF_BOOL x = nitf_ExtensionsIterator_notEqualTo(&handle, &it2.getHandle()); + if (!x) return false; + return true; + } + + bool operator!=(const nitf::ExtensionsIterator& it2) + { + return this->notEqualTo((nitf::ExtensionsIterator&)it2); + } + + /*! + * Increment the iterator + */ + void increment() + { + nitf_ExtensionsIterator_increment(&handle); + } + + //! Increment the iterator (postfix) + void operator++(int ) + { + increment(); + } + + //! Increment the iterator (prefix) + void operator++() + { + increment(); + } + + //! Get the TRE from the iterator + nitf::TRE operator*() + { + return get(); + } + + /*! + * Get the TRE from the iterator + */ + nitf::TRE get() + { + nitf_TRE * x = nitf_ExtensionsIterator_get(&handle); + return nitf::TRE(x); + } + +private: + nitf_ExtensionsIterator handle; + nitf_Error error; +}; + + +/*! + * \class Extensions + * \brief The C++ wrapper for the nitf_Extensions + * + * The Extensions may exist in almost any part of the + * NITF file. In essence, this object is a data store + * of information that was provided in data extensions. + */ +DECLARE_CLASS(Extensions) +{ +public: + +typedef nitf::ExtensionsIterator Iterator; + + //! Copy constructor + Extensions(const Extensions & x) + { + setNative(x.getNative()); + } + + //! Assignment Operator + Extensions & operator=(const Extensions & x) + { + if (&x != this) + setNative(x.getNative()); + return *this; + } + + //! Set native object + Extensions(nitf_Extensions * x) + { + setNative(x); + getNativeOrThrow(); + } + + //! Constructor + Extensions() throw(nitf::NITFException) + { + setNative(nitf_Extensions_construct(&error)); + getNativeOrThrow(); + setManaged(false); + } + + //! Clone + nitf::Extensions clone() throw(nitf::NITFException) + { + nitf::Extensions dolly(nitf_Extensions_clone(getNativeOrThrow(), &error)); + dolly.setManaged(false); + return dolly; + } + + ~Extensions(){} + + /*! + * Insert a TRE into the extensions section + * \param name The name of the TRE + * \param tre The TRE itself + */ + void appendTRE(nitf::TRE & tre) throw(nitf::NITFException) + { + //if the TRE is already managed, we throw an Exception + if (tre.isManaged()) + throw nitf::NITFException(Ctxt("The given TRE is already managed by the library. Try cloning it first.")); + + NITF_BOOL x = nitf_Extensions_appendTRE(getNative(), + tre.getNativeOrThrow(), &error); + if (!x) + throw nitf::NITFException(&error); + tre.setManaged(true); //The TRE is now owned by the underlying extensions object + } + + /*! + * Get the TREs by the name given + * \param The name of the TRE to get + * \return A List of TREs matching the specified name + */ + nitf::List getTREsByName(const std::string& name) throw(except::NoSuchKeyException) + { + nitf_List* x = nitf_Extensions_getTREsByName(getNative(), name.c_str()); + if (!x) + throw except::NoSuchKeyException(); + return nitf::List(x); + } + + /*! + * Sometimes we're simply not interested in a TRE section + * at all. We can kill the entire list of TREs using + * this function. + * \param name The name of the TREs to erase + */ + void removeTREsByName(const std::string& name) + { + nitf_Extensions_removeTREsByName(getNative(), name.c_str()); + } + + /*! + * Remove the TRE at the given iterator position + * \param iter The ExtensionsIterator to erase + */ + void remove(Iterator& iter) + { + nitf_TRE* tre = nitf_Extensions_remove( + getNative(), &iter.getHandle(), &error); + if (tre) delete tre; + } + + + //! Get the hash + nitf::HashTable getHash() + { + return nitf::HashTable(getNativeOrThrow()->hash); + } + + //! Set the hash + void setHash(nitf::HashTable & value) + { + //release the currently "owned" one + nitf::HashTable ht = nitf::HashTable(getNativeOrThrow()->hash); + ht.setManaged(false); + + //have the library manage the "new" one + getNativeOrThrow()->hash = value.getNative(); + value.setManaged(true); + } + + /*! + * Checks if the TRE exists + * \param The name of the TRE + */ + bool exists(const std::string& key) + { + NITF_BOOL x = nitf_Extensions_exists(getNative(), key.c_str()); + return x ? true : false; + } + + /*! + * Get the begin iterator + * \return The iterator pointing to the first TRE + */ + Iterator begin() + { + nitf_ExtensionsIterator x = nitf_Extensions_begin(getNative()); + return nitf::ExtensionsIterator(x); + } + + /*! + * Get the end iterator + * \return The iterator pointing PAST the last TRE (null) + */ + Iterator end() + { + nitf_ExtensionsIterator x = nitf_Extensions_end(getNative()); + return nitf::ExtensionsIterator(x); + } + + nitf::Uint64 computeLength(nitf::Version version) + { + return nitf_Extensions_computeLength(getNative(), version, &error); + } + +private: + nitf_Error error; +}; +} +#endif diff --git a/modules/c++/nitf/include/nitf/Field.hpp b/modules/c++/nitf/include/nitf/Field.hpp new file mode 100644 index 000000000..5547d5eff --- /dev/null +++ b/modules/c++/nitf/include/nitf/Field.hpp @@ -0,0 +1,429 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_FIELD_HPP__ +#define __NITF_FIELD_HPP__ + +#include "nitf/Field.h" +#include "nitf/System.hpp" +#include "nitf/NITFException.hpp" +#include "nitf/Object.hpp" +#include "nitf/HashTable.hpp" +#include "nitf/List.hpp" +#include "nitf/DateTime.hpp" +#include +#include + +/*! + * \file Field.hpp + * \brief Contains wrapper implementation for Field + */ + +namespace nitf +{ +/*! + * \class Field + * \brief The C++ wrapper for the nitf_Field + * + * The Field is a generic type object that allows storage + * and casting of data amongst disparate data types. + */ +class Field : public nitf::Object +{ + +public: +enum FieldType + { + BCS_A = NITF_BCS_A, + BCS_N = NITF_BCS_N, + BINARY = NITF_BINARY + }; + + Field & operator=(const char * value) throw(nitf::NITFException) + { + set(value); + return *this; + } + + Field & operator=(const std::string& value) + { + set(value); + return *this; + } + + Field & operator=(nitf::Int8 value) + { + set(value); + return *this; + } + + Field & operator=(nitf::Int16 value) + { + set(value); + return *this; + } + + Field & operator=(nitf::Int32 value) + { + set(value); + return *this; + } + + Field & operator=(nitf::Int64 value) + { + set(value); + return *this; + } + + Field & operator=(nitf::Uint8 value) + { + set(value); + return *this; + } + + Field & operator=(nitf::Uint16 value) + { + set(value); + return *this; + } + + Field & operator=(nitf::Uint32 value) + { + set(value); + return *this; + } + + Field & operator=(nitf::Uint64 value) + { + set(value); + return *this; + } + + Field & operator=(float value) + { + set(value); + return *this; + } + + Field & operator=(double value) + { + set(value); + return *this; + } + + //! Copy constructor + Field(const Field & x) + { + setNative(x.getNative()); + } + + //! Assignment Operator + Field & operator=(const Field & x) + { + if (&x != this) + setNative(x.getNative()); + return *this; + } + + //! Set native object + Field(nitf_Field * field) + { + setNative(field); + getNativeOrThrow(); + } + + Field(NITF_DATA * x) + { + setNative((nitf_Field*)x); + getNativeOrThrow(); + } + + Field & operator=(NITF_DATA * x) + { + setNative((nitf_Field*)x); + getNativeOrThrow(); + return *this; + } + + //! Destructor + ~Field() {} + + void set(nitf::Uint8 data) + { + if (!nitf_Field_setUint32(getNativeOrThrow(), + nitf::Uint32(data), &error)) + throw nitf::NITFException(&error); + } + + void set(nitf::Uint16 data) + { + if (!nitf_Field_setUint32(getNativeOrThrow(), + nitf::Uint32(data), &error)) + throw nitf::NITFException(&error); + } + + void set(nitf::Uint32 data) throw(nitf::NITFException) + { + NITF_BOOL x = nitf_Field_setUint32(getNativeOrThrow(), data, &error); + if (!x) + throw nitf::NITFException(&error); + } + + void set(nitf::Uint64 data) throw(nitf::NITFException) + { + NITF_BOOL x = nitf_Field_setUint64(getNativeOrThrow(), data, &error); + if (!x) + throw nitf::NITFException(&error); + } + + void set(nitf::Int8 data) + { + if (!nitf_Field_setInt32(getNativeOrThrow(), + nitf::Uint32(data), &error)) + throw nitf::NITFException(&error); + } + + void set(nitf::Int16 data) + { + if (!nitf_Field_setInt32(getNativeOrThrow(), + nitf::Uint32(data), &error)) + throw nitf::NITFException(&error); + } + + void set(nitf::Int32 data) + { + if (!nitf_Field_setInt32(getNativeOrThrow(), + nitf::Uint32(data), &error)) + throw nitf::NITFException(&error); + } + + void set(nitf::Int64 data) + { + if (!nitf_Field_setInt64(getNativeOrThrow(), + nitf::Uint32(data), &error)) + throw nitf::NITFException(&error); + } + + void set(float data) + { + if (!nitf_Field_setReal(getNativeOrThrow(), + "f", false, double(data), &error)) + throw nitf::NITFException(&error); + } + + void set(double data) + { + if (!nitf_Field_setReal(getNativeOrThrow(), + "f", false, data, &error)) + throw nitf::NITFException(&error); + } + + void set(const char * data) throw(nitf::NITFException) + { + NITF_BOOL x = nitf_Field_setString(getNativeOrThrow(), (char*)data, &error); + if (!x) + throw nitf::NITFException(&error); + } + + void set(const std::string& data) throw(nitf::NITFException) + { + const NITF_BOOL x = + nitf_Field_setString(getNativeOrThrow(), data.c_str(), &error); + if (!x) + throw nitf::NITFException(&error); + } + + void set(const nitf::DateTime& dateTime, + const std::string& format = NITF_DATE_FORMAT_21) throw(nitf::NITFException) + { + const NITF_BOOL x = nitf_Field_setDateTime(getNativeOrThrow(), + dateTime.getNative(), format.c_str(), &error); + if (!x) + throw nitf::NITFException(&error); + } + + nitf::DateTime asDateTime(const std::string& format = NITF_DATE_FORMAT_21) throw(nitf::NITFException) + { + nitf_DateTime* const dateTime = + nitf_Field_asDateTime(getNativeOrThrow(), format.c_str(), + &error); + if (!dateTime) + { + throw nitf::NITFException(&error); + } + return nitf::DateTime(dateTime); + } + + //! Get the type + FieldType getType() const + { + return (FieldType)getNativeOrThrow()->type; + } + + //! Set the type + void setType(FieldType type) + { + getNativeOrThrow()->type = (nitf_FieldType)type; + } + + //! Get the data + char * getRawData() const + { + return getNativeOrThrow()->raw; + } + //! Set the data + void setRawData(char * raw, size_t length) throw(nitf::NITFException) + { + set(raw, length); + } + + //! Get the data length + size_t getLength() const + { + return getNativeOrThrow()->length; + } + + /** + * Resizes the field to the given length. + * Use this method with caution as it can resize a field to be larger than + * it should be, according to specs. + */ + void resize(size_t length) + { + nitf_Field *field = getNativeOrThrow(); + NITF_BOOL resizable = field->resizable; + field->resizable = 1; + + if (!nitf_Field_resizeField(field, length, &error)) + throw nitf::NITFException(&error); + field->resizable = resizable; + } + + operator nitf::Uint8() const + { + nitf::Uint8 data; + get(&data, NITF_CONV_UINT, sizeof(nitf::Uint8)); + return data; + } + + operator nitf::Uint16() const + { + nitf::Uint16 data; + get(&data, NITF_CONV_UINT, sizeof(nitf::Uint16)); + return data; + } + + operator nitf::Uint32() const + { + nitf::Uint32 data; + get(&data, NITF_CONV_UINT, sizeof(nitf::Uint32)); + return data; + } + + operator nitf::Uint64() const + { + nitf::Uint64 data; + get(&data, NITF_CONV_UINT, sizeof(nitf::Uint64)); + return data; + } + + operator nitf::Int8() const + { + nitf::Int8 data; + get(&data, NITF_CONV_INT, sizeof(nitf::Int8)); + return data; + } + + operator nitf::Int16() const + { + nitf::Int16 data; + get(&data, NITF_CONV_INT, sizeof(nitf::Int16)); + return data; + } + + operator nitf::Int32() const + { + nitf::Int32 data; + get(&data, NITF_CONV_INT, sizeof(nitf::Int32)); + return data; + } + + operator nitf::Int64() const + { + nitf::Int64 data; + get(&data, NITF_CONV_INT, sizeof(nitf::Int64)); + return data; + } + + operator float() const + { + float data; + get(&data, NITF_CONV_REAL, sizeof(float)); + return data; + } + + operator double() const + { + double data; + get(&data, NITF_CONV_REAL, sizeof(double)); + return data; + } + + operator std::string() const + { + return toString(); + } + + std::string toString() const + { + return std::string(getNativeOrThrow()->raw, + getNativeOrThrow()->length ); + } + +private: + Field(){} //private -- does not make sense to construct a Field from scratch + + //! get the value + void get(NITF_DATA* outval, nitf::ConvType vtype, size_t length) const + { + nitf_Error e; + NITF_BOOL x = nitf_Field_get(getNativeOrThrow(), outval, vtype, length, &e); + if (!x) + throw nitf::NITFException(&e); + } + + //! set the value + void set(NITF_DATA* inval, size_t length) throw(nitf::NITFException) + { + NITF_BOOL x = nitf_Field_setRawData(getNativeOrThrow(), inval, length, &error); + if (!x) + throw nitf::NITFException(&error); + } + + nitf_Error error; + + operator char*() const; // Don't allow this cast ever. +}; + +} + +#endif diff --git a/modules/c++/nitf/include/nitf/FieldWarning.hpp b/modules/c++/nitf/include/nitf/FieldWarning.hpp new file mode 100644 index 000000000..7a18374dc --- /dev/null +++ b/modules/c++/nitf/include/nitf/FieldWarning.hpp @@ -0,0 +1,116 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_FIELDWARNING_HPP__ +#define __NITF_FIELDWARNING_HPP__ + +#include "nitf/FieldWarning.h" +#include "nitf/System.hpp" +#include "nitf/NITFException.hpp" +#include "nitf/Field.hpp" +#include "nitf/Object.hpp" +#include + +/*! + * \file FieldWarning.hpp + * \brief Contains wrapper implementation for FieldWarning + */ + +namespace nitf +{ + +/*! + * \class FieldWarning + * \brief The C++ wrapper for the nitf_FieldWarning + * + * Describes a warning associated with a field in the NITF + */ +DECLARE_CLASS(FieldWarning) +{ +public: + //! Copy constructor + FieldWarning(const FieldWarning & x) + { + setNative(x.getNative()); + } + + //! Assignment Operator + FieldWarning & operator=(const FieldWarning & x) + { + if (&x != this) + setNative(x.getNative()); + return *this; + } + + //! Set native object + FieldWarning(nitf_FieldWarning * x) + { + setNative(x); + getNativeOrThrow(); + } + + /*! + * Constructor + * \param fileOffset The offset in the file to the field + * \param field A string representing the NITF field + * \param value The NITF field value + * \param expectation A string describing the expected field value + */ + FieldWarning(nitf::Off fileOffset, const std::string& fieldName, + nitf::Field & field, const std::string& expectation) + throw(nitf::NITFException) + { + setNative(nitf_FieldWarning_construct(fileOffset, fieldName.c_str(), + field.getNative(), expectation.c_str(), &error)); + getNativeOrThrow(); + setManaged(false); + } + + ~FieldWarning(){} + + //! Get the fileOffset + nitf::Off getFileOffset() const + { + return getNativeOrThrow()->fileOffset; + } + //! Get the field + std::string getFieldName() const + { + return std::string(getNativeOrThrow()->fieldName); + } + //! Get the value + nitf::Field getField() + { + return nitf::Field(getNativeOrThrow()->field); + } + //! Get the expectation + std::string getExpectation() const + { + return std::string(getNativeOrThrow()->expectation); + } + +private: + nitf_Error error; +}; + +} +#endif diff --git a/modules/c++/nitf/include/nitf/FileHeader.hpp b/modules/c++/nitf/include/nitf/FileHeader.hpp new file mode 100644 index 000000000..b7c02b528 --- /dev/null +++ b/modules/c++/nitf/include/nitf/FileHeader.hpp @@ -0,0 +1,196 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_FILEHEADER_HPP__ +#define __NITF_FILEHEADER_HPP__ + +#include "nitf/FileHeader.h" +#include "nitf/System.hpp" +#include "nitf/FileSecurity.hpp" +#include "nitf/Extensions.hpp" +#include "nitf/ComponentInfo.hpp" +#include "nitf/Field.hpp" +#include "nitf/Object.hpp" +#include + +/*! + * \file FileHeader.hpp + * \brief Contains wrapper implementation for FileHeader + */ + +namespace nitf +{ + +/*! + * \class FileHeader + * \brief The C++ wrapper for the nitf_FileHeader + * + * A structure representing the in-memory layout of the NITF file. + * + */ +DECLARE_CLASS(FileHeader) +{ +public: + + //! Copy constructor + FileHeader(const FileHeader & x); + + //! Assignment Operator + FileHeader & operator=(const FileHeader & x); + + //! Set native object + FileHeader(nitf_FileHeader * x); + + //! Constructor + FileHeader() throw(nitf::NITFException); + + //! Clone + nitf::FileHeader clone() throw(nitf::NITFException); + + ~FileHeader(); + + //! Get the fileHeader + nitf::Field getFileHeader(); + + //! Get the fileVersion + nitf::Field getFileVersion(); + + //! Get the complianceLevel + nitf::Field getComplianceLevel(); + + //! Get the systemType + nitf::Field getSystemType(); + + //! Get the originStationID + nitf::Field getOriginStationID(); + + //! Get the fileDateTime + nitf::Field getFileDateTime(); + + //! Get the fileTitle + nitf::Field getFileTitle(); + + //! Get the classification + nitf::Field getClassification(); + + //! Get the securityGroup + nitf::FileSecurity getSecurityGroup(); + + //! Set the securityGroup + void setSecurityGroup(nitf::FileSecurity value); + + //! Get the messageCopyNum + nitf::Field getMessageCopyNum(); + + //! Get the messageNumCopies + nitf::Field getMessageNumCopies(); + + //! Get the encrypted + nitf::Field getEncrypted(); + + //! Get the backgroundColor + nitf::Field getBackgroundColor(); + + //! Get the originatorName + nitf::Field getOriginatorName(); + + //! Get the originatorPhone + nitf::Field getOriginatorPhone(); + + //! Get the fileLength + nitf::Field getFileLength(); + + //! Get the headerLength + nitf::Field getHeaderLength(); + + //! Get the numImages + nitf::Field getNumImages(); + + //! Get the numGraphics + nitf::Field getNumGraphics(); + + //! Get the numLabels + nitf::Field getNumLabels(); + + //! Get the numTexts + nitf::Field getNumTexts(); + + //! Get the numDataExtensions + nitf::Field getNumDataExtensions(); + + //! Get the numReservedExtensions + nitf::Field getNumReservedExtensions(); + + //! Get the imageInfo + nitf::ComponentInfo getImageInfo(int i) + throw(except::IndexOutOfRangeException); + + //! Get the graphicInfo + nitf::ComponentInfo getGraphicInfo(int i) + throw(except::IndexOutOfRangeException); + + //! Get the labelInfo + nitf::ComponentInfo getLabelInfo(int i) + throw(except::IndexOutOfRangeException); + + //! Get the textInfo + nitf::ComponentInfo getTextInfo(int i) + throw(except::IndexOutOfRangeException); + + //! Get the dataExtensionInfo + nitf::ComponentInfo getDataExtensionInfo(int i) + throw(except::IndexOutOfRangeException); + + //! Get the reservedExtensionInfo + nitf::ComponentInfo getReservedExtensionInfo(int i) + throw(except::IndexOutOfRangeException); + + //! Get the userDefinedHeaderLength + nitf::Field getUserDefinedHeaderLength(); + + //! Get the userDefinedOverflow + nitf::Field getUserDefinedOverflow(); + + //! Get the extendedHeaderLength + nitf::Field getExtendedHeaderLength(); + + //! Get the extendedHeaderOverflow + nitf::Field getExtendedHeaderOverflow(); + + //! Get the userDefinedSection + nitf::Extensions getUserDefinedSection(); + + //! Set the userDefinedSection + void setUserDefinedSection(nitf::Extensions value); + + //! Get the extendedSection + nitf::Extensions getExtendedSection(); + + //! Set the extendedSection + void setExtendedSection(nitf::Extensions value); + +private: + nitf_Error error; +}; + +} +#endif diff --git a/modules/c++/nitf/include/nitf/FileSecurity.hpp b/modules/c++/nitf/include/nitf/FileSecurity.hpp new file mode 100644 index 000000000..0afdef3f2 --- /dev/null +++ b/modules/c++/nitf/include/nitf/FileSecurity.hpp @@ -0,0 +1,117 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_FILESECURITY_HPP__ +#define __NITF_FILESECURITY_HPP__ + +#include "nitf/FileSecurity.h" +#include "nitf/System.hpp" +#include "nitf/Field.hpp" +#include "nitf/Object.hpp" +#include + +/*! + * \file FileSecurity.hpp + * \brief Contains wrapper implementation for FileSecurity + */ + +namespace nitf +{ + +/*! + * \class FileSecurity + * \brief The C++ wrapper for the nitf_FileSecurity + * + * Contains fields pertaining to security information from + * the NITF file. + */ +DECLARE_CLASS(FileSecurity) +{ +public: + //! Copy constructor + FileSecurity(const FileSecurity & x); + + //! Assignment Operator + FileSecurity & operator=(const FileSecurity & x); + + //! Set native object + FileSecurity(nitf_FileSecurity * x); + + //! Constructor + FileSecurity() throw(nitf::NITFException); + + //! Clone + nitf::FileSecurity clone() throw(nitf::NITFException); + + ~FileSecurity(); + + //! Get the classificationSystem + nitf::Field getClassificationSystem(); + + //! Get the codewords + nitf::Field getCodewords(); + + //! Get the controlAndHandling + nitf::Field getControlAndHandling(); + + //! Get the releasingInstructions + nitf::Field getReleasingInstructions(); + + //! Get the declassificationType + nitf::Field getDeclassificationType(); + + //! Get the declassificationDate + nitf::Field getDeclassificationDate(); + + //! Get the declassificationExemption + nitf::Field getDeclassificationExemption(); + + //! Get the downgrade + nitf::Field getDowngrade(); + + //! Get the downgradeDateTime + nitf::Field getDowngradeDateTime(); + + //! Get the classificationText + nitf::Field getClassificationText(); + + //! Get the classificationAuthorityType + nitf::Field getClassificationAuthorityType(); + + //! Get the classificationAuthority + nitf::Field getClassificationAuthority(); + + //! Get the classificationReason + nitf::Field getClassificationReason(); + + //! Get the securitySourceDate + nitf::Field getSecuritySourceDate(); + + //! Get the securityControlNumber + nitf::Field getSecurityControlNumber(); + +private: + nitf_Error error; +}; + +} +#endif diff --git a/modules/c++/nitf/include/nitf/GraphicSegment.hpp b/modules/c++/nitf/include/nitf/GraphicSegment.hpp new file mode 100644 index 000000000..bcd4b995e --- /dev/null +++ b/modules/c++/nitf/include/nitf/GraphicSegment.hpp @@ -0,0 +1,92 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_GRAPHICSEGMENT_HPP__ +#define __NITF_GRAPHICSEGMENT_HPP__ + +#include "nitf/GraphicSegment.h" +#include "nitf/System.hpp" +#include "nitf/NITFException.hpp" +#include "nitf/GraphicSubheader.hpp" +#include "nitf/Object.hpp" +#include + +/*! + * \file GraphicSegment.hpp + * \brief Contains wrapper implementation for GraphicSegment + */ + +namespace nitf +{ + +/*! + * \class GraphicSegment + * \brief The C++ wrapper for the nitf_GraphicSegment + */ +DECLARE_CLASS(GraphicSegment) +{ +public: + //! Copy constructor + GraphicSegment(const GraphicSegment & x); + + //! Assignment Operator + GraphicSegment & operator=(const GraphicSegment & x); + + //! Set native object + GraphicSegment(nitf_GraphicSegment * x); + + //! Constructor + GraphicSegment() throw(nitf::NITFException); + + GraphicSegment(NITF_DATA * x); + + GraphicSegment & operator=(NITF_DATA * x); + + //! Clone + nitf::GraphicSegment clone() throw(nitf::NITFException); + + ~GraphicSegment(); + + //! Get the subheader + nitf::GraphicSubheader getSubheader(); + + //! Set the subheader + void setSubheader(nitf::GraphicSubheader & value); + + //! Get the offset + nitf::Uint64 getOffset() const; + + //! Set the offset + void setOffset(nitf::Uint64 value); + + //! Get the end + nitf::Uint64 getEnd() const; + + //! Set the end + void setEnd(nitf::Uint64 value); + +private: + nitf_Error error; +}; + +} +#endif diff --git a/modules/c++/nitf/include/nitf/GraphicSubheader.hpp b/modules/c++/nitf/include/nitf/GraphicSubheader.hpp new file mode 100644 index 000000000..8b2e08d8b --- /dev/null +++ b/modules/c++/nitf/include/nitf/GraphicSubheader.hpp @@ -0,0 +1,130 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_GRAPHICSUBHEADER_HPP__ +#define __NITF_GRAPHICSUBHEADER_HPP__ + +#include "nitf/GraphicSubheader.h" +#include "nitf/Object.hpp" +#include "nitf/Field.hpp" +#include "nitf/FileSecurity.hpp" +#include "nitf/Extensions.hpp" +#include + +/*! + * \file GraphicSubheader.hpp + * \brief Contains wrapper implementation for GraphicSubheader + */ + +namespace nitf +{ + +/*! + * \class GraphicSubheader + * \brief The C++ wrapper for the nitf_GraphicSubheader + */ +DECLARE_CLASS(GraphicSubheader) +{ +public: + //! Copy constructor + GraphicSubheader(const GraphicSubheader & x); + + //! Assignment Operator + GraphicSubheader & operator=(const GraphicSubheader & x); + + //! Set native object + GraphicSubheader(nitf_GraphicSubheader * x); + + //! Default Constructor + GraphicSubheader() throw(nitf::NITFException); + + //! Clone + nitf::GraphicSubheader clone() throw(nitf::NITFException); + + ~GraphicSubheader(); + + //! Get the filePartType + nitf::Field getFilePartType(); + + //! Get the graphicID + nitf::Field getGraphicID(); + + //! Get the name + nitf::Field getName(); + + //! Get the securityClass + nitf::Field getSecurityClass(); + + //! Get the securityGroup + nitf::FileSecurity getSecurityGroup(); + + //! Set the securityGroup + void setSecurityGroup(nitf::FileSecurity value); + + //! Get the encrypted + nitf::Field getEncrypted(); + + //! Get the stype + nitf::Field getStype(); + + //! Get the res1 + nitf::Field getRes1(); + + //! Get the displayLevel + nitf::Field getDisplayLevel(); + + //! Get the attachmentLevel + nitf::Field getAttachmentLevel(); + + //! Get the location + nitf::Field getLocation(); + + //! Get the bound1Loc + nitf::Field getBound1Loc(); + + //! Get the color + nitf::Field getColor(); + + //! Get the bound2Loc + nitf::Field getBound2Loc(); + + //! Get the res2 + nitf::Field getRes2(); + + //! Get the extendedHeaderLength + nitf::Field getExtendedHeaderLength(); + + //! Get the extendedHeaderOverflow + nitf::Field getExtendedHeaderOverflow(); + + //! Get the extendedSection + nitf::Extensions getExtendedSection(); + + //! Set the extendedSection + void setExtendedSection(nitf::Extensions value); + +private: + nitf_Error error; +}; + +} +#endif diff --git a/modules/c++/nitf/include/nitf/Handle.hpp b/modules/c++/nitf/include/nitf/Handle.hpp new file mode 100644 index 000000000..55797c45b --- /dev/null +++ b/modules/c++/nitf/include/nitf/Handle.hpp @@ -0,0 +1,146 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_HANDLE_HPP__ +#define __NITF_HANDLE_HPP__ + +/*! + * \file Handle.hpp + * \brief Contains handle wrapper to manage shared native objects + */ + +#include +#include "nitf/System.hpp" +#include + +namespace nitf +{ + +/*! + * \class Handle + * \brief This class is the base definition of a Handle + */ +class Handle +{ +public: + Handle() : refCount(0) {} + virtual ~Handle() {} + + //! Get the ref count + int getRef() { return refCount; } + + //! Increment the ref count + int incRef() + { + mutex.lock(); + refCount++; + mutex.unlock(); + return refCount; + } + + //! Decrement the ref count + int decRef() + { + mutex.lock(); + if (refCount > 0) + refCount--; + mutex.unlock(); + return refCount; + } + +protected: + static sys::Mutex mutex; + int refCount; +}; + + +/*! + * \struct MemoryDestructor + * \brief A functor that is used to destruct underlying memory contained + * in handles. Extend this class to custom-destruct objects. + */ +template +struct MemoryDestructor +{ + virtual void operator()(T* /*nativeObject*/) {} + virtual ~MemoryDestructor() {} +}; + + +/*! + * \class Handle + * \brief This class wraps a pointer and keeps track of + * the number of times it is referenced through the incRef + * and decRef functions. + */ +template > +class BoundHandle : public Handle +{ +private: + Class_T* handle; + int managed; + +public: + //! Create handle from native object + BoundHandle(Class_T* h = NULL) : handle(h), managed(1) {} + + //! Destructor + virtual ~BoundHandle() + { + //call the destructor, to destroy the object + if(handle && managed <= 0) + { + DestructFunctor_T functor; + functor(handle); + } + } + + //! Assign from native object + Handle& operator=(Class_T* h) + { + if (h != handle) + handle = h; + return *this; + } + + //! Get the native object + Class_T* get() { return handle; } + + //! Get the address of then native object + Class_T** getAddress() { return &handle; } + + /*! + * Sets whether or not the native object is "managed" by the underlying + * C library. Most objects are in turn managed, but some (such as Records) + * are not. By setting the object to be un-managed, the native object will + * be passed to the DestructFunctor_T functor, and most likely destroyed, + * depending on what the functor does. + */ + void setManaged(bool flag) { managed += flag ? 1 : (managed == 0 ? 0 : -1); } + + //! Is the native object managed? + bool isManaged() { return managed > 0; } + +}; + +} +#endif diff --git a/modules/c++/nitf/include/nitf/HandleManager.hpp b/modules/c++/nitf/include/nitf/HandleManager.hpp new file mode 100644 index 000000000..f11eb6862 --- /dev/null +++ b/modules/c++/nitf/include/nitf/HandleManager.hpp @@ -0,0 +1,102 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_HANDLE_MANAGER_HPP__ +#define __NITF_HANDLE_MANAGER_HPP__ + +#include +#include +#include +#include +#include "nitf/Handle.hpp" + +namespace nitf +{ +class HandleManager +{ +private: +typedef void* CAddress; + + std::map mHandleMap; //! map for storing the handles + sys::Mutex mMutex; //! mutex used for locking the map + +public: + HandleManager() {} + virtual ~HandleManager() {} + + template + bool hasHandle(T* object) + { + if (!object) return false; + mt::CriticalSection obtainLock(&mMutex); + return mHandleMap.find(object) != mHandleMap.end(); + } + + template + BoundHandle* acquireHandle(T* object) + { + if (!object) return NULL; + mt::CriticalSection obtainLock(&mMutex); + if (mHandleMap.find(object) == mHandleMap.end()) + { + BoundHandle* handle = + new BoundHandle(object); + mHandleMap[object] = handle; + } + BoundHandle* handle = + (BoundHandle*)mHandleMap[object]; + obtainLock.manualUnlock(); + + handle->incRef(); + return handle; + } + + template + void releaseHandle(T* object) + { + mt::CriticalSection obtainLock(&mMutex); + std::map::iterator it = mHandleMap.find(object); + if (it != mHandleMap.end()) + { + Handle* handle = (Handle*)it->second; + if (handle->decRef() <= 0) + { + mHandleMap.erase(it); + obtainLock.manualUnlock(); + delete handle; + } + } + } +}; + +/*! + * Create a Singleton registry for managing the Handles + * + * Note that this will NOT get deleted at exit, so there will be a memory loss + * the size of a HandleManager object (about 50 bytes). We can't let the singleton + * be deleted at exit, in case other singletons contain references to these + * handles. + */ +typedef mt::Singleton HandleRegistry; + +} +#endif diff --git a/modules/c++/nitf/include/nitf/HashTable.hpp b/modules/c++/nitf/include/nitf/HashTable.hpp new file mode 100644 index 000000000..7a799b150 --- /dev/null +++ b/modules/c++/nitf/include/nitf/HashTable.hpp @@ -0,0 +1,257 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_HASHTABLE_HPP__ +#define __NITF_HASHTABLE_HPP__ + +#include "nitf/System.hpp" +#include "nitf/NITFException.hpp" +#include "nitf/Pair.hpp" +#include "nitf/List.hpp" +#include "nitf/Object.hpp" +#include +#include +#include + +/*! + * \file HashTable.hpp + * \brief Contains wrapper implementation for HashTable + */ + +namespace nitf +{ +class HashTable; //forward declaration + +/*! + * HashTable Iterator Functor + */ +class HashIterator +{ +public: + virtual ~HashIterator(){} + virtual void operator()(nitf::HashTable* ht, + nitf::Pair& pair, + NITF_DATA* userData) = 0; +}; + + +/*! + * \class HashTableIterator + * \brief The C++ wrapper for the nitf_HashTableIterator + * + * Iterates a hash table, unordered. + */ +class HashTableIterator +{ +public: + //! Constructor + HashTableIterator() {} + + //! Destructor + ~HashTableIterator() {} + + //! Copy constructor + HashTableIterator(const HashTableIterator & x) { handle = x.handle; } + + //! Assignment Operator + HashTableIterator & operator=(const HashTableIterator & x); + + //! Set native object + HashTableIterator(nitf_HashTableIterator x) { setHandle(x); } + + //! Get native object + nitf_HashTableIterator & getHandle(); + + //! Check to see if two iterators are equal + bool equals(nitf::HashTableIterator& it2); + + //! Check to see if two iterators are not equal + bool notEqualTo(nitf::HashTableIterator& it2); + + //! Increment the iterator + void increment(); + + bool operator==(const nitf::HashTableIterator& it2); + + bool operator!=(const nitf::HashTableIterator& it2); + + //! Increment the iterator (postfix); + void operator++(int x); + + //! Increment the iterator by a specified amount + HashTableIterator & operator+=(int x); + + HashTableIterator operator+(int x); + + //! Increment the iterator (prefix); + void operator++() { increment(); } + + //! Get the data + nitf::Pair operator*() { return get(); } + + //! Get the data + nitf::Pair get() { return nitf_HashTableIterator_get(&handle); } + + +private: + nitf_HashTableIterator handle; + + //! Set native object + void setHandle(nitf_HashTableIterator x) { handle = x; } +}; + + +/*! + * \class HashTable + * \brief The C++ wrapper for the nitf_HashTable + */ +DECLARE_CLASS(HashTable) +{ +public: + + //! Copy constructor + HashTable(const HashTable & x); + + //! Assignment Operator + HashTable & operator=(const HashTable & x); + + //! Set native object + HashTable(nitf_HashTable * x); + + /*! + * Constructor + * \param nbuckets The size of the hash + */ + HashTable(int nbuckets = 5) throw(nitf::NITFException); + + //! Clone + nitf::HashTable clone(NITF_DATA_ITEM_CLONE cloner) + throw(nitf::NITFException); + + /*! + * This function controls ownership. You may elect either + * policy, NITF_DATA_ADOPT, or NITF_DATA_RETAIN_OWNER. + * Here is the difference. In the hash table, the data field + * is a pointer to an object. That object may have been allocated + * by you, or it may be static, I don't know. You may wish to + * remove it yourself, or I may be told to remove it for you. + * If you do not tell me, I will assume that you own it. + */ + void setPolicy(int policy); + + /*! + * Remove data from the hash table. Here is the removal policy: + * You ask for this object to be removed from the hash + * - We remove the pair from the hash and delete the pair + * associated with the storage + * - We give you back your data, if it exists + * - You are expected to delete the data we give you + * + */ + NITF_DATA* remove(const std::string& key); + + /*! + * Assigns the hash function to a "good" default. + */ + void initDefaults(); + + ~HashTable(); + + /*! + * Check to see whether such a key exists in the table + * \param The key to lookup + * \return True if exists, False otherwise. + */ + bool exists(const std::string& key); + + /*! + * Debug tool to find out whats in the hash table + */ + void print(); + + /*! + * For each item in the hash table, do something (slow); + * \param fn The function to perform + */ + void foreach(HashIterator& fun, NITF_DATA* userData = NULL) + throw(nitf::NITFException); + + /*! + * Insert this key/data pair into the hash table + * \param key The key to insert under + * \param data The data to insert into the second value of the pair + */ + void insert(const std::string& key, NITF_DATA* data) + throw(nitf::NITFException); + + /*! + * Templated insert, allowing us to insert nitf::Objects + */ + template + void insert(const std::string& key, nitf::Object object) + throw(nitf::NITFException) + { + insert(key, (NITF_DATA*)object.getNative()); + } + + /*! + * Retrieve some key/value pair from the hash table + * \param key The key to retrieve by + * \return The key/value pair + */ + nitf::Pair find(const std::string& key) throw(except::NoSuchKeyException); + + nitf::Pair operator[] (const std::string& key) throw(except::NoSuchKeyException); + + //! Get the buckets + nitf::List getBucket(int i) throw(nitf::NITFException); + + //! Get the nbuckets + int getNumBuckets() const; + + //! Get the adopt flag + int getAdopt() const; + + /*! + * Get the begin iterator + * \return The iterator pointing to the first item in the list + */ + nitf::HashTableIterator begin(); + + /*! + * Get the end iterator + * \return The iterator pointing to PAST the last item in the list (null); + */ + nitf::HashTableIterator end(); + +private: + + std::vector mBuckets; + nitf_Error error; + + //! Clear the buckets + void clearBuckets(); + +}; + +} +#endif diff --git a/modules/c++/nitf/include/nitf/IOHandle.hpp b/modules/c++/nitf/include/nitf/IOHandle.hpp new file mode 100644 index 000000000..5a11598e6 --- /dev/null +++ b/modules/c++/nitf/include/nitf/IOHandle.hpp @@ -0,0 +1,77 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_IOHANDLE_HPP__ +#define __NITF_IOHANDLE_HPP__ + +#include + +#include "nitf/NITFException.hpp" +#include "nitf/System.hpp" +#include "nitf/IOInterface.hpp" + +/*! + * \file IOHandle.hpp + * \brief Contains wrapper implementation for IOHandle + */ + +namespace nitf +{ + +/*! + * \class IOHandle + * \brief The C++ wrapper of the nitf_IOHandle + */ +class IOHandle : public IOInterface +{ + +public: + + /*! + * Default constructor. Only here for compatibility purposes. + * Use the other constructor + */ + /*explicit IOHandle() + { + }*/ + + IOHandle(const std::string& fname, + nitf::AccessFlags access = NITF_ACCESS_READONLY, + nitf::CreationFlags creation = NITF_OPEN_EXISTING) + throw (nitf::NITFException); + + IOHandle(const char* fname, + nitf::AccessFlags access = NITF_ACCESS_READONLY, + nitf::CreationFlags creation = NITF_OPEN_EXISTING) + throw (nitf::NITFException); + +private: + static + nitf_IOInterface* + open(const char* fname, + nitf::AccessFlags access, + nitf::CreationFlags creation) throw (nitf::NITFException); + +}; + +} +#endif diff --git a/modules/c++/nitf/include/nitf/IOInterface.hpp b/modules/c++/nitf/include/nitf/IOInterface.hpp new file mode 100644 index 000000000..9b77e4443 --- /dev/null +++ b/modules/c++/nitf/include/nitf/IOInterface.hpp @@ -0,0 +1,96 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_IO_INTERFACE_HPP__ +#define __NITF_IO_INTERFACE_HPP__ + +#include "nitf/System.hpp" +#include "nitf/Object.hpp" +#include + +/*! + * \file IOInterface.hpp + */ +namespace nitf +{ + +struct IOInterfaceDestructor : public nitf::MemoryDestructor +{ + ~IOInterfaceDestructor() + { + } + void operator()(nitf_IOInterface *io); +}; + +/*! + * \class IOInterface + * \brief The C++ wrapper for the nitf_IOInterface + */ +class IOInterface : public nitf::Object +{ +public: + // Set native object + IOInterface(nitf_IOInterface * x) + { + setNative(x); + getNativeOrThrow(); + } + + //! Copy constructor + IOInterface(const IOInterface& lhs) + { + setNative(lhs.getNative()); + } + + //! Destructor + virtual ~IOInterface() { } + + //! Assignment Operator + IOInterface & operator=(const IOInterface & x) + { + if (&x != this) + setNative(x.getNative()); + return *this; + } + + void read(char * buf, size_t size); + + void write(const char * buf, size_t size); + + bool canSeek() const; + + nitf::Off seek(nitf::Off offset, int whence); + + nitf::Off tell() const; + + nitf::Off getSize() const; + + int getMode() const; + + void close(); + +protected: + mutable nitf_Error error; +}; + +} +#endif diff --git a/modules/c++/nitf/include/nitf/ImageReader.hpp b/modules/c++/nitf/include/nitf/ImageReader.hpp new file mode 100644 index 000000000..5eec3c043 --- /dev/null +++ b/modules/c++/nitf/include/nitf/ImageReader.hpp @@ -0,0 +1,88 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_IMAGE_READER_HPP__ +#define __NITF_IMAGE_READER_HPP__ + +#include "nitf/ImageReader.h" +#include "nitf/Object.hpp" +#include "nitf/BlockingInfo.hpp" +#include + +/*! + * \file ImageReader.hpp + * \brief Contains wrapper implementation for ImageReader + */ + +namespace nitf +{ + +/*! + * \class ImageReader + * \brief The C++ wrapper for the nitf_ImageReader + */ +DECLARE_CLASS(ImageReader) +{ +public: + //! Copy constructor + ImageReader(const ImageReader & x); + + //! Assignment Operator + ImageReader & operator=(const ImageReader & x); + + //! Set native object + ImageReader(nitf_ImageReader * x); + + ~ImageReader(); + + //! Get the blocking info + nitf::BlockingInfo getBlockingInfo() throw (nitf::NITFException); + + /*! + * Read a sub-window. See ImageIO::read for more details. + * \param subWindow The sub-window to read + * \param user User-defined data buffers for read + * \param padded Returns TRUE if pad pixels may have been read + */ + void read(nitf::SubWindow & subWindow, nitf::Uint8 ** user, int * padded) + throw (nitf::NITFException); + + /*! + * Read a block directly from file + * \param blockNumber + * \param blockSize Returns block size + * \return The read block + * (something must be done with buffer before next call) + */ + const nitf::Uint8* readBlock(nitf::Uint32 blockNumber, + nitf::Uint64* blockSize); + + //! Set read caching + void setReadCaching(); + +private: + nitf_Error error; + ImageReader() throw(nitf::NITFException){} +}; + +} +#endif diff --git a/modules/c++/nitf/include/nitf/ImageSegment.hpp b/modules/c++/nitf/include/nitf/ImageSegment.hpp new file mode 100644 index 000000000..0d2f63034 --- /dev/null +++ b/modules/c++/nitf/include/nitf/ImageSegment.hpp @@ -0,0 +1,92 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_IMAGESEGMENT_HPP__ +#define __NITF_IMAGESEGMENT_HPP__ + +#include "nitf/ImageSegment.h" +#include "nitf/ImageSubheader.hpp" +#include "nitf/System.hpp" +#include "nitf/NITFException.hpp" +#include "nitf/Object.hpp" +#include + +/*! + * \file ImageSegment.hpp + * \brief Contains wrapper implementation for ImageSegment + */ + +namespace nitf +{ + +/*! + * \class ImageSegment + * \brief The C++ wrapper for the nitf_ImageSegment + */ +DECLARE_CLASS(ImageSegment) +{ +public: + //! Copy constructor + ImageSegment(const ImageSegment & x); + + //! Assignment Operator + ImageSegment & operator=(const ImageSegment & x); + + //! Set native object + ImageSegment(nitf_ImageSegment * x); + + //! Constructor + ImageSegment() throw(nitf::NITFException); + + ImageSegment(NITF_DATA * x); + + ImageSegment & operator=(NITF_DATA * x); + + //! Clone + nitf::ImageSegment clone() throw(nitf::NITFException); + + ~ImageSegment(); + + //! Get the subheader + nitf::ImageSubheader getSubheader(); + + //! Set the subheader + void setSubheader(nitf::ImageSubheader & value); + + //! Get the imageOffset + nitf::Uint64 getImageOffset() const; + + //! Set the imageOffset + void setImageOffset(nitf::Uint64 value); + + //! Get the imageEnd + nitf::Uint64 getImageEnd() const; + + //! Set the imageEnd + void setImageEnd(nitf::Uint64 value); + +private: + nitf_Error error; +}; + +} +#endif diff --git a/modules/c++/nitf/include/nitf/ImageSource.hpp b/modules/c++/nitf/include/nitf/ImageSource.hpp new file mode 100644 index 000000000..b11ce1f6d --- /dev/null +++ b/modules/c++/nitf/include/nitf/ImageSource.hpp @@ -0,0 +1,77 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_IMAGESOURCE_HPP__ +#define __NITF_IMAGESOURCE_HPP__ + +#include "nitf/ImageSource.h" +#include "nitf/BandSource.hpp" +#include "nitf/System.hpp" +#include "nitf/NITFException.hpp" +#include "nitf/Object.hpp" +#include + +/*! + * \file ImageSource.hpp + * \brief Contains wrapper implementation for ImageSource + */ + +namespace nitf +{ + +/*! + * \class ImageSource + * \brief The C++ wrapper for the nitf_ImageSource + */ +DECLARE_CLASS(ImageSource) +{ +public: + //! Copy constructor + ImageSource(const ImageSource & x); + + //! Assignment Operator + ImageSource & operator=(const ImageSource & x); + + //! Set native object + ImageSource(nitf_ImageSource * x); + + /*! + * Constructor + */ + ImageSource() throw(nitf::NITFException); + + ~ImageSource(); + + //! Add a band + void addBand(nitf::BandSource bandSource) throw(nitf::NITFException); + + //! Get a band + nitf::BandSource getBand(int n) throw (nitf::NITFException); + +private: + nitf_Error error; + // keep a list of the bands + std::vector mBands; +} +; +} +#endif diff --git a/modules/c++/nitf/include/nitf/ImageSubheader.hpp b/modules/c++/nitf/include/nitf/ImageSubheader.hpp new file mode 100644 index 000000000..0f1013a33 --- /dev/null +++ b/modules/c++/nitf/include/nitf/ImageSubheader.hpp @@ -0,0 +1,372 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_IMAGESUBHEADER_HPP__ +#define __NITF_IMAGESUBHEADER_HPP__ + +#include "nitf/ImageSubheader.h" +#include "nitf/Object.hpp" +#include "nitf/NITFException.hpp" +#include "nitf/BandInfo.hpp" +#include "nitf/List.hpp" +#include "nitf/FileSecurity.hpp" +#include "nitf/Extensions.hpp" +#include "nitf/System.hpp" +#include + +/*! + * \file ImageSubheader.hpp + * \brief Contains wrapper implementation for ImageSubheader + */ + +namespace nitf +{ + +/*! + * \class ImageSubheader + * \brief The C++ wrapper for the nitf_ImageSubheader + */ +DECLARE_CLASS(ImageSubheader) +{ +public: + + //! Copy constructor + ImageSubheader(const ImageSubheader & x); + + //! Assignment Operator + ImageSubheader & operator=(const ImageSubheader & x); + + //! Set native object + ImageSubheader(nitf_ImageSubheader * x); + + //! Constructor + ImageSubheader() throw(nitf::NITFException); + + + //! Clone + nitf::ImageSubheader clone() throw(nitf::NITFException); + + /*! + * Destructor + */ + ~ImageSubheader(); + + /*! + * Set the pixel type and band related information + * \param pvtype Pixel value type + * \param nbpp Number of bits/pixel + * \param abpp Actual number of bits/pixel + * \param justification Pixel justification + * \param irep Image representation + * \param icat Image category + * \param bandCount Number of bands + * \param bands Band information object list + */ + void setPixelInformation(std::string pvtype, + nitf::Uint32 nbpp, + nitf::Uint32 abpp, + std::string justification, + std::string irep, std::string icat, + std::vector& bands) + throw(nitf::NITFException); + + + /*! + * @deprecated - here for backwards compatibility + * bandCount WILL get ignored + */ + void setPixelInformation(std::string pvtype, + nitf::Uint32 nbpp, + nitf::Uint32 abpp, + std::string justification, + std::string irep, std::string icat, + nitf::Uint32 bandCount, + std::vector& bands) + throw(nitf::NITFException); + + + /*! + * This function allows the user to set the corner coordinates from a + * set of decimal values. This function only supports CornersTypes of + * NITF_GEO or NITF_DECIMAL. Others will trigger an error with code + * NITF_ERR_INVALID_PARAMETER + * + * In order to set up the type, you should declare a double corners[4][2]; + * The first dimension is used for the corner itself, and the second + * dimension is for lat (0) or lon (1). + * + * The corners MUST be oriented to correspond to + * + * corners[0] = (0, 0), + * corners[1] = (0, MaxCol), + * corners[2] = (MaxRow, MaxCol) + * corners[3] = (MaxRow, 0) + * + * following in line with 2500C. + */ + void setCornersFromLatLons(nitf::CornersType type, + double corners[4][2]) + throw(nitf::NITFException); + + + /*! + * This function allows the user to extract corner coordinates as a + * set of decimal values. This function only supports CornersTypes of + * NITF_GEO or NITF_DECIMAL. Others will trigger an error with code + * NITF_ERR_INVALID_PARAMETER + * + * The output corners will be oriented to correspond to + * + * corners[0] = (0, 0), + * corners[1] = (0, MaxCol), + * corners[2] = (MaxRow, MaxCol) + * corners[3] = (MaxRow, 0) + * + * following in line with 2500C. + */ + void getCornersAsLatLons(double corners[4][2]) throw(nitf::NITFException); + + /*! + * Get the type of corners. This will return NITF_CORNERS_UNKNOWN + * in the event that it is not 'U', 'N', 'S', 'D', or 'G'. + * + */ + nitf::CornersType getCornersType() throw(nitf::NITFException); + + /*! + * Set the image dimensions and blocking info. + * The user specifies the number of rows and columns in the image, number + * of rows and columns per block, and blocking mode. The number of blocks + * per row and column is calculated. The NITF 2500C large block option can + * be selected for either dimension by setting the corresponding block + * dimension to 0. + * + * \param numRows The number of rows + * \param numCols The number of columns + * \param numRowsPerBlock The number of rows/block + * \param numColsPerBlock The number of columns/block + * \param imode Image mode + */ + void setBlocking(nitf::Uint32 numRows, + nitf::Uint32 numCols, + nitf::Uint32 numRowsPerBlock, + nitf::Uint32 numColsPerBlock, + const std::string& imode) throw(nitf::NITFException); + + /*! + * Compute blocking parameters + * The user specifies the number of rows and columns in the image and the + * number of rows and columns per block. The number of blocks per row and + * column is calculated. The NITF 2500C large block option can be selected + * for either dimension by setting the corresponding block dimension to 0. + * If numRowsPerBlock or numColsPerBlock is over the NITF maximum, it is + * reduced to 0 per 2500C. + * + * The number of blocks per column is a backwards way of saying the number + * of rows of blocks. So the numBlocksPerCol calculation involves row counts + * and numBlocksPerRow calculation involves column counts. + * + * \param numRows The number of rows + * \param numCols The number of columns + * \param numRowsPerBlock The number of rows/block + * \param numColsPerBlock The number of columns/block + * \param numBlocksPerCol The number of rows of blocks + * \param numBlocksPerRow The number of columns of blocks + */ + static + void computeBlocking(nitf::Uint32 numRows, + nitf::Uint32 numCols, + nitf::Uint32& numRowsPerBlock, + nitf::Uint32& numColsPerBlock, + nitf::Uint32& numBlocksPerCol, + nitf::Uint32& numBlocksPerRow); + + /*! + * Set the image dimensions and blocking. + * + * The blocking is set to the simplest possible blocking given the + * dimension, no blocking if possible. Blocking mode is set to B. Whether + * or not blocking masks are generated is dependent on the compression + * code at the time the image is written. NITF 2500C large block + * dimensions are not set by this function. The more general set blocking + * function must be used to specify this blocking option. + * + * \param numRows The number of rows + * \param numCols The number of columns + */ + void setDimensions(nitf::Uint32 numRows, nitf::Uint32 numCols) + throw(nitf::NITFException); + + + //! Get the number of bands + nitf::Uint32 getBandCount() throw(nitf::NITFException); + + //! Create new bands + void createBands(nitf::Uint32 numBands) throw(nitf::NITFException); + + //! Insert the given comment at the given index (zero-indexed); + int insertImageComment(std::string comment, int index); + + //! Remove the given comment at the given index (zero-indexed); + void removeImageComment(int index); + + //! Get the filePartType + nitf::Field getFilePartType(); + + //! Get the imageId + nitf::Field getImageId(); + + //! Get the imageDateAndTime + nitf::Field getImageDateAndTime(); + + //! Get the targetId + nitf::Field getTargetId(); + + //! Get the imageTitle + nitf::Field getImageTitle(); + + //! Get the imageSecurityClass + nitf::Field getImageSecurityClass(); + + //! Get the securityGroup + nitf::FileSecurity getSecurityGroup(); + + //! Set the securityGroup + void setSecurityGroup(nitf::FileSecurity value); + + //! Get the encrypted + nitf::Field getEncrypted(); + + //! Get the imageSource + nitf::Field getImageSource(); + + //! Get the numRows + nitf::Field getNumRows(); + + //! Get the numCols + nitf::Field getNumCols(); + + //! Get the pixelValueType + nitf::Field getPixelValueType(); + + //! Get the imageRepresentation + nitf::Field getImageRepresentation(); + + //! Get the imageCategory + nitf::Field getImageCategory(); + + //! Get the actualBitsPerPixel + nitf::Field getActualBitsPerPixel(); + + //! Get the pixelJustification + nitf::Field getPixelJustification(); + + //! Get the imageCoordinateSystem + nitf::Field getImageCoordinateSystem(); + + //! Get the cornerCoordinates + nitf::Field getCornerCoordinates(); + + //! Get the numImageComments + nitf::Field getNumImageComments(); + + //! Get the imageComments + nitf::List getImageComments(); + + //! Get the imageCompression + nitf::Field getImageCompression(); + + //! Get the compressionRate + nitf::Field getCompressionRate(); + + //! Get the numImageBands + nitf::Field getNumImageBands(); + + //! Get the numMultispectralImageBands + nitf::Field getNumMultispectralImageBands(); + + //! Get the bandInfo + nitf::BandInfo getBandInfo(nitf::Uint32 band) throw(nitf::NITFException); + + //! Get the imageSyncCode + nitf::Field getImageSyncCode(); + + //! Get the imageMode + nitf::Field getImageMode(); + + //! Get the numBlocksPerRow + nitf::Field getNumBlocksPerRow(); + + //! Get the numBlocksPerCol + nitf::Field getNumBlocksPerCol(); + + //! Get the numPixelsPerHorizBlock + nitf::Field getNumPixelsPerHorizBlock(); + + //! Get the numPixelsPerVertBlock + nitf::Field getNumPixelsPerVertBlock(); + + //! Get the numBitsPerPixel + nitf::Field getNumBitsPerPixel(); + + //! Get the imageDisplayLevel + nitf::Field getImageDisplayLevel(); + + //! Get the imageAttachmentLevel + nitf::Field getImageAttachmentLevel(); + + //! Get the imageLocation + nitf::Field getImageLocation(); + + //! Get the imageMagnification + nitf::Field getImageMagnification(); + + //! Get the userDefinedImageDataLength + nitf::Field getUserDefinedImageDataLength(); + + //! Get the userDefinedOverflow + nitf::Field getUserDefinedOverflow(); + + //! Get the extendedHeaderLength + nitf::Field getExtendedHeaderLength(); + + //! Get the extendedHeaderOverflow + nitf::Field getExtendedHeaderOverflow(); + + //! Get the userDefinedSection + nitf::Extensions getUserDefinedSection(); + + //! Set the userDefinedSection + void setUserDefinedSection(nitf::Extensions value); + + //! Get the extendedSection + nitf::Extensions getExtendedSection(); + + //! Set the extendedSection + void setExtendedSection(nitf::Extensions value); + +private: + nitf_Error error; +}; + +} +#endif diff --git a/modules/c++/nitf/include/nitf/ImageWriter.hpp b/modules/c++/nitf/include/nitf/ImageWriter.hpp new file mode 100644 index 000000000..ff25c6ed9 --- /dev/null +++ b/modules/c++/nitf/include/nitf/ImageWriter.hpp @@ -0,0 +1,88 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_IMAGE_WRITER_HPP__ +#define __NITF_IMAGE_WRITER_HPP__ + +#include "nitf/ImageWriter.h" +#include "nitf/Object.hpp" +#include "nitf/WriteHandler.hpp" +#include "nitf/ImageSource.hpp" +#include "nitf/ImageSubheader.hpp" +#include + +/*! + * \file ImageWriter.hpp + * \brief Contains wrapper implementation for ImageWriter + */ + +namespace nitf +{ + +/*! + * \class ImageWriter + * \brief The C++ wrapper for the nitf_ImageWriter + */ +class ImageWriter : public WriteHandler +{ +public: + /*! + * Constructor + * \param subheader The subheader of the Image to write + */ + ImageWriter(nitf::ImageSubheader& subheader) throw(nitf::NITFException); + + // Set native object + ImageWriter(nitf_ImageWriter *x) : WriteHandler(x) + { + } + + ~ImageWriter(); + + /*! + * Attach an image source from which to write. + * \param imageSource The image source from which to write + */ + void attachSource(nitf::ImageSource imageSource) + throw (nitf::NITFException); + + //! Enable/disable cached writes + void setWriteCaching(int enable); + + //! Enable/disable direct block writes (if you don't know what this means, don't use it) + void setDirectBlockWrite(int enable); + + /*! + * Function allows the user access to the product's pad pixels. + * For example, if you wanted transparent pixels for fill, you would + * set this function using arguments (0, 1) + */ + void setPadPixel(nitf::Uint8* value, nitf::Uint32 length); + +private: + nitf_Error error; +// bool mAdopt; +// nitf::ImageSource* mImageSource; +}; + +} +#endif diff --git a/modules/c++/nitf/include/nitf/LabelSegment.hpp b/modules/c++/nitf/include/nitf/LabelSegment.hpp new file mode 100644 index 000000000..0ef4c736c --- /dev/null +++ b/modules/c++/nitf/include/nitf/LabelSegment.hpp @@ -0,0 +1,90 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_LABELSEGMENT_HPP__ +#define __NITF_LABELSEGMENT_HPP__ + +#include "nitf/LabelSegment.h" +#include "nitf/LabelSubheader.hpp" +#include "nitf/Object.hpp" +#include + +/*! + * \file LabelSegment.hpp + * \brief Contains wrapper implementation for LabelSegment + */ + +namespace nitf +{ + +/*! + * \class LabelSegment + * \brief The C++ wrapper for the nitf_LabelSegment + */ +DECLARE_CLASS(LabelSegment) +{ +public: + //! Copy constructor + LabelSegment(const LabelSegment & x); + + //! Assignment Operator + LabelSegment & operator=(const LabelSegment & x); + + //! Set native object + LabelSegment(nitf_LabelSegment * x); + + //! Constructor + LabelSegment() throw(nitf::NITFException); + + LabelSegment(NITF_DATA * x); + + LabelSegment & operator=(NITF_DATA * x); + + //! Clone + nitf::LabelSegment clone() throw(nitf::NITFException); + + ~LabelSegment(); + + //! Get the subheader + nitf::LabelSubheader getSubheader(); + + //! Set the subheader + void setSubheader(nitf::LabelSubheader & value); + + //! Get the offset + nitf::Uint64 getOffset() const; + + //! Set the offset + void setOffset(nitf::Uint64 value); + + //! Get the end + nitf::Uint64 getEnd() const; + + //! Set the end + void setEnd(nitf::Uint64 value); + +private: + nitf_Error error; +}; + +} +#endif diff --git a/modules/c++/nitf/include/nitf/LabelSubheader.hpp b/modules/c++/nitf/include/nitf/LabelSubheader.hpp new file mode 100644 index 000000000..8923253ef --- /dev/null +++ b/modules/c++/nitf/include/nitf/LabelSubheader.hpp @@ -0,0 +1,128 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_LABELSUBHEADER_HPP__ +#define __NITF_LABELSUBHEADER_HPP__ + +#include "nitf/LabelSubheader.h" +#include "nitf/Object.hpp" +#include "nitf/Field.hpp" +#include "nitf/FileSecurity.hpp" +#include "nitf/Extensions.hpp" +#include + +/*! + * \file LabelSubheader.hpp + * \brief Contains wrapper implementation for LabelSubheader + */ + +namespace nitf +{ + +/*! + * \class LabelSubheader + * \brief The C++ wrapper for the nitf_LabelSubheader + */ +DECLARE_CLASS(LabelSubheader) +{ +public: + + //! Copy constructor + LabelSubheader(const LabelSubheader & x); + + //! Assignment Operator + LabelSubheader & operator=(const LabelSubheader & x); + + //! Set native object + LabelSubheader(nitf_LabelSubheader * x); + + //! Default Constructor + LabelSubheader() throw(nitf::NITFException); + + //! Clone + nitf::LabelSubheader clone() throw(nitf::NITFException); + + ~LabelSubheader(); + + //! Get the filePartType + nitf::Field getFilePartType(); + + //! Get the labelID + nitf::Field getLabelID(); + + //! Get the securityClass + nitf::Field getSecurityClass(); + + //! Get the securityGroup + nitf::FileSecurity getSecurityGroup(); + + //! Set the securityGroup + void setSecurityGroup(nitf::FileSecurity value); + + //! Get the encrypted + nitf::Field getEncrypted(); + + //! Get the fontStyle + nitf::Field getFontStyle(); + + //! Get the cellWidth + nitf::Field getCellWidth(); + + //! Get the cellHeight + nitf::Field getCellHeight(); + + //! Get the displayLevel + nitf::Field getDisplayLevel(); + + //! Get the attachmentLevel + nitf::Field getAttachmentLevel(); + + //! Get the locationRow + nitf::Field getLocationRow(); + + //! Get the locationColumn + nitf::Field getLocationColumn(); + + //! Get the textColor + nitf::Field getTextColor(); + + //! Get the backgroundColor + nitf::Field getBackgroundColor(); + + //! Get the extendedHeaderLength + nitf::Field getExtendedHeaderLength(); + + //! Get the extendedHeaderOverflow + nitf::Field getExtendedHeaderOverflow(); + + //! Get the extendedSection + nitf::Extensions getExtendedSection(); + + //! Set the extendedSection + void setExtendedSection(nitf::Extensions value); + +private: + nitf_Error error; +}; + +} +#endif diff --git a/modules/c++/nitf/include/nitf/List.hpp b/modules/c++/nitf/include/nitf/List.hpp new file mode 100644 index 000000000..c12d42783 --- /dev/null +++ b/modules/c++/nitf/include/nitf/List.hpp @@ -0,0 +1,304 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_LIST_HPP__ +#define __NITF_LIST_HPP__ + +#include "nitf/System.hpp" +#include "nitf/Object.hpp" +#include + +/*! + * \file List.hpp + * \brief Contains wrapper implementation for List + */ + +namespace nitf +{ + +/*! + * \class ListNode + * \brief The C++ wrapper for the nitf_ListNode + * + * This object provides the base for a chain in a hash. + * It is a doubly-linked list with pair data (the first of + * which is copied, the second of which is not). + */ +DECLARE_CLASS(ListNode) +{ +public: + //! Constructor + ListNode() {} + + //! Copy constructor + ListNode(const ListNode & x) { setNative(x.getNative()); } + + //! Assignment Operator + ListNode & operator=(const ListNode & x); + + //! Set native object + ListNode(nitf_ListNode * x); + + /*! + * Constructor + * \param prev The previous node + * \param next The next node + * \param data The data to insert into the list + */ + ListNode(nitf::ListNode & prev, nitf::ListNode & next, NITF_DATA* data) + throw(nitf::NITFException); + + //! Destructor + ~ListNode() {} + + //! Get the data + NITF_DATA * getData() const; + + //! Set the data + void setData(NITF_DATA * value); + +private: + friend class List; + friend class ListIterator; + + nitf_Error error; +}; + +/*! + * \class ListIterator + * \brief The C++ wrapper for the nitf_ListIterator + * + * Iterates a linked list. + */ +class ListIterator +{ +public: + //! Constructor + ListIterator() {} + + //! Destructor + ~ListIterator() {} + + //! Copy constructor + ListIterator(const ListIterator & x) { handle = x.handle; } + + //! Assignment Operator + ListIterator & operator=(const ListIterator & x); + + //! Set native object + ListIterator(nitf_ListIterator x); + + //! Get native object + nitf_ListIterator & getHandle(); + + //! Checks to see if two iterators are equal + bool equals(nitf::ListIterator& it2); + + //! Checks to see if two iterators are not equal + bool notEqualTo(nitf::ListIterator& it2); + + bool operator==(const nitf::ListIterator& it2); + + bool operator!=(const nitf::ListIterator& it2); + + //! Increment the iterator + void increment(); + + //! Increment the iterator (postfix); + void operator++(int x); + + //! Increment the iterator by a specified amount + ListIterator & operator+=(int x); + + ListIterator operator+(int x); + + //! Increment the iterator (prefix); + void operator++() { increment(); } + + //! Get the data + NITF_DATA* operator*() { return get(); } + + //! Get the data + NITF_DATA* get() { return nitf_ListIterator_get(&handle); } + + //! Get the current + nitf::ListNode & getCurrent() { return mCurrent; } + +private: + nitf_ListIterator handle; + nitf::ListNode mCurrent; + + //! Set native object + void setHandle(nitf_ListIterator x) + { + handle = x; + setMembers(); + } + + //! Reset member objects + void setMembers() { mCurrent.setNative(handle.current); } + + //! Set the current + void setCurrent(const nitf::ListNode & value) { mCurrent = value; } +}; + + +/*! + * \class List + * \brief The C++ wrapper for the nitf_List + * + * This object is the controller for the ListNode nodes. + * It contains a pointer to the first and last items in its set. + */ +DECLARE_CLASS(List) +{ +public: + + //! Copy constructor + List(const List & x); + + //! Assignment Operator + List & operator=(const List & x); + + //! Set native object + List(nitf_List * x); + + /*! + * Is our chain empty? + * \return True if so, False otherwise + */ + bool isEmpty(); + + /*! + * Push something onto the front of our chain. Note, as + * usual we REFUSE to allocate your data for you. If you + * need a copy, make one up front. + * \param data The data to push to the front + */ + void pushFront(NITF_DATA* data) throw(nitf::NITFException); + + template + void pushFront(nitf::Object object) throw(nitf::NITFException) + { + pushFront((NITF_DATA*)object.getNativeOrThrow()); + } + + /*! + * Push something onto the back of our chain + * \param data The data to push onto the back + */ + void pushBack(NITF_DATA* data) throw(nitf::NITFException); + + template + void pushBack(T object) throw(nitf::NITFException) + { + pushBack((NITF_DATA*)object.getNativeOrThrow()); + } + + /*! + * Pop the node off the front and return it. + * We check the first item to see if it exists. If it does, + * we then fill in, and return the value. + * \return The link we popped off + */ + NITF_DATA* popFront(); + + /*! + * Pop the node off the back and return it. + * We check the first item to see if it exists. If it does, + * we then fill in, and return the value. + * \return The link we popped off + */ + NITF_DATA* popBack(); + + //! Constructor + List() throw(nitf::NITFException); + + //! Clone + nitf::List clone(NITF_DATA_ITEM_CLONE cloner) throw(nitf::NITFException); + + //! Destructor + ~List(); + + /*! + * Get the begin iterator + * \return The iterator pointing to the first item in the list + */ + nitf::ListIterator begin(); + + /*! + * Get the end iterator + * \return The iterator pointing to PAST the last item in the list (null); + */ + nitf::ListIterator end(); + + /*! + * Insert data into the chain BEFORE the iterator, and make + * the iterator point at the new node. + * + * If the iterator is pointing to NULL, we will insert into the + * back of this list. If it is pointing to the beginning, we + * will insert into the front. + * + * If the iterator is pointing to something else, we will insert + * after the iterator (same case, in practice as pointing to the + * beginning). + * \param iter The iterator to insert before + * \param data This is a pointer assignment, not a data copy + */ + void insert(nitf::ListIterator & iter, NITF_DATA* data) throw(nitf::NITFException); + + template + void insert(nitf::ListIterator & iter, nitf::Object object) throw(nitf::NITFException) + { + insert(iter, (NITF_DATA*)object.getNativeOrThrow()); + } + + /*! + * Remove the data from an arbitrary point in the list. + * This WILL NOT delete the data, but it will make sure + * that we have successfully updated the chain. The + * iterator is moved to the value that the current node + * pointed to (the next value). + * \param where Where to remove, this will be updated to the NEXT position + * \return We don't know how to delete YOUR object, so return it. + */ + NITF_DATA* remove(nitf::ListIterator & where); + + //! Get the first + nitf::ListNode getFirst(); + + //! Get the last + nitf::ListNode getLast(); + + //! Returns the size of the list + size_t getSize(); + + //! Returns the data at the given index + NITF_DATA* operator[] (size_t index) throw(nitf::NITFException); + +private: + nitf_Error error; +}; + +} +#endif diff --git a/modules/c++/nitf/include/nitf/LookupTable.hpp b/modules/c++/nitf/include/nitf/LookupTable.hpp new file mode 100644 index 000000000..d5a64fa2b --- /dev/null +++ b/modules/c++/nitf/include/nitf/LookupTable.hpp @@ -0,0 +1,86 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_LOOKUPTABLE_HPP__ +#define __NITF_LOOKUPTABLE_HPP__ + +#include +#include +#include "nitf/LookupTable.h" +#include "nitf/NITFException.hpp" +#include "nitf/Object.hpp" + +/*! + * \file LookupTable.hpp + * \brief Contains wrapper implementation for LookupTable + */ + +namespace nitf +{ +/*! + * \class LookupTable + * \brief The C++ wrapper for the nitf_LookupTable + */ +class LookupTable : public nitf::Object +{ +public: + //! Create an uninitialized table of the specified dimensions + LookupTable(size_t numTables, size_t numEntries); + + //! Create a table of the specified dimensions initialized to 'table' + LookupTable(const unsigned char* table, + size_t numTables, + size_t numEntries); + + //! Copy constructor + LookupTable(const LookupTable & x); + + //! Assignment Operator + LookupTable & operator=(const LookupTable & x); + + //! Set native object + LookupTable(nitf_LookupTable * x); + + //! Destructor + ~LookupTable(); + + //! Get the tables + size_t getTables() const; + + //! Get the entries + size_t getEntries() const; + + //! Get the table + unsigned char * getTable() const; + + //! Set the table and dimensions + void setTable(const unsigned char* table, + size_t numTables, + size_t numEntries); + +private: + nitf_Error error; + +}; + +} +#endif diff --git a/modules/c++/nitf/include/nitf/MemoryIO.hpp b/modules/c++/nitf/include/nitf/MemoryIO.hpp new file mode 100644 index 000000000..9654c0ddc --- /dev/null +++ b/modules/c++/nitf/include/nitf/MemoryIO.hpp @@ -0,0 +1,61 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_MEMORY_IO_HPP__ +#define __NITF_MEMORY_IO_HPP__ + +#include "nitf/NITFException.hpp" +#include "nitf/System.hpp" +#include "nitf/IOInterface.hpp" + +/*! + * \file MemoryIO.hpp + * \brief Contains wrapper implementation for BufferAdapter + */ + +namespace nitf +{ + +/*! + * \class MemoryIO + * \brief The C++ wrapper of the nitf_BufferAdapter + */ +class MemoryIO : public IOInterface +{ +public: + MemoryIO(size_t capacity) throw(nitf::NITFException); + + // If adopt is true, the memory will be deallocated via NRT_FREE(), so it + // must be allocated via NRT_MALLOC() (not new[]). If adopt is false, the + // allocation method does not matter. + MemoryIO(void* buffer, size_t size, bool adopt = false) + throw(nitf::NITFException); + +private: + static + nitf_IOInterface* create(void* buffer, + size_t size, + bool adopt) throw(nitf::NITFException); +}; + +} +#endif diff --git a/modules/c++/nitf/include/nitf/NITFException.hpp b/modules/c++/nitf/include/nitf/NITFException.hpp new file mode 100644 index 000000000..aa66aabac --- /dev/null +++ b/modules/c++/nitf/include/nitf/NITFException.hpp @@ -0,0 +1,98 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_EXCEPTION_HPP__ +#define __NITF_EXCEPTION_HPP__ + +#include +#include "nitf/System.hpp" + +/*! + * \file NITFException.hpp + * \brief NITFException class for nitf objects + */ +namespace nitf +{ +/*! + * \class NITFException + * \brief The C++ wrapper for the nitf_Error + */ +class NITFException : public except::Exception +{ +public: + /*! + * Construct from native object + * \param error The native nitf_Error object + */ + NITFException(const nitf_Error* error) + { + const except::Context context(std::string(error->file), + error->line, + std::string(error->func), + std::string(""), + std::string(error->message)); + mMessage = context.getMessage(); + mTrace.pushContext( context ); + } + /*! + * Construct from native object with message + * \param error The native nitf_Error object + * \param message Additional error message + */ + NITFException(const nitf_Error* error, const std::string& message) + { + const except::Context context( + std::string(error->file), + error->line, + std::string(error->func), + std::string(""), + message + " (" + std::string(error->message) + ")"); + mMessage = context.getMessage(); + mTrace.pushContext( context ); + } + /*! + * Construct from Context + * \param c The Context + */ + NITFException(const except::Context& c) : except::Exception(c){} + + /*! + * Construct from an error message + * \param message The error message + */ + NITFException(const std::string& message) : except::Exception(message){} + + /*! + * Construct from Throwable and Context + * \param t The Throwable + * \param c The Context + */ + NITFException(const except::Throwable& t, const except::Context& c) : + except::Exception(t, c){} + + //! Destructor + virtual ~NITFException(){} + +} +; +} +#endif diff --git a/modules/c++/nitf/include/nitf/Object.hpp b/modules/c++/nitf/include/nitf/Object.hpp new file mode 100644 index 000000000..1c048cdca --- /dev/null +++ b/modules/c++/nitf/include/nitf/Object.hpp @@ -0,0 +1,191 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_OBJECT_HPP__ +#define __NITF_OBJECT_HPP__ + +#include "nitf/Handle.hpp" +#include "nitf/HandleManager.hpp" +#include "nitf/NITFException.hpp" + +namespace nitf +{ +// Forward declarations so we can say we are friends +class List; +class HashTable; +/*! + * \class Object + * \brief This class keeps a pointer to an underlying C object + * The Object class does not destroy or clone any memory. The sole purpose is + * to act as a non-invasive wrapper on top of objects internal to the NITF + * C core. + */ +template > +class Object +{ +protected: + //make the nitf containers friends + friend class List; + friend class HashTable; + + //! The handle to the underlying memory + BoundHandle* mHandle; + + //! Release this object's hold on the handle + void releaseHandle() + { + if (mHandle && mHandle->get()) + HandleRegistry::getInstance().releaseHandle(mHandle->get()); + mHandle = NULL; + } + + //! Set native object + virtual void setNative(T* nativeObj) + { + //only modify if it is a different native object + if (!isValid() || mHandle->get() != nativeObj) + { + releaseHandle(); + mHandle = HandleRegistry::getInstance().template acquireHandle(nativeObj); + } + } + +public: + //! Constructor + Object() : mHandle(NULL) {} + + //! Destructor + virtual ~Object() { releaseHandle(); } + + //! Is the object valid (native object not null)? + virtual bool isValid() const + { + return getNative() != NULL; + } + + //! Equality, based on handle + bool operator==(const Object& obj) + { + return mHandle == obj.mHandle; + } + + //! Inequality, based on handle + bool operator!=(const Object& obj) + { + return !(operator==(obj)); + } + + //! Get native object + virtual T * getNative() const + { + return mHandle ? mHandle->get() : NULL; + } + + //! Get native object + virtual T * getNativeOrThrow() const throw(nitf::NITFException) + { + T* val = getNative(); + if (val) + return val; + throw nitf::NITFException(Ctxt("Invalid handle")); + } + + /*! + * Returns an ID that represents this particular object. + * Currently, the ID is the stringized memory address of the underlying + * memory. + * + * This *could* be used for equality purposes, however be warned, because + * as objects die, etc. the memory addresses will be reused. + */ + std::string getObjectID() const + { + return FmtX("%p", getNative()); + } + + bool isManaged() const { return isValid() && mHandle->isManaged(); } + + /*! + * Set the management of the underlying memory + * + * \param flag if flag is true, the underlying library will adopt and manage the memory + * if flag is false, the memory can be freed when refcount == 0 + */ + void setManaged(bool flag) + { + if (isValid()) + mHandle->setManaged(flag); + } + + std::string toString() const + { + return getObjectID(); + } + + void incRef() + { + mHandle->incRef(); + } + + void decRef() + { + mHandle->decRef(); + } + +}; + + +} + +/*! + * Helpful macro that can be used to define a Class with name _Name. + * The macro will also create a sub-class of MemoryDestructor which knows + * how to destroy the underlying memory for the given object. The _Name + * gets stringified/concat'ed in the macro. An example for 'Record' would + * look like this: + * + * struct RecordDestructor : public MemoryDestructor \ + * { \ + * ~RecordDestructor(){} \ + * virtual void operator()(nitf_Record *nativeObject) \ + * { nitf_Record_destruct(&nativeObject); } \ + * }; \ + * \ + * class Record : public Object + * + * This works for all nitf objects that *can* be destroyed, and who have a + * corresponding nitf_##_destruct method. + */ + +#define DECLARE_CLASS_IN(_Name, _Package) \ + struct _Name##Destructor : public nitf::MemoryDestructor<_Package##_##_Name> \ + { \ + ~_Name##Destructor(){} \ + virtual void operator()(_Package##_##_Name *nativeObject) \ + { _Package##_##_Name##_destruct(&nativeObject); } \ + }; \ + \ + class _Name : public nitf::Object<_Package##_##_Name, _Name##Destructor> + +#define DECLARE_CLASS(_Name) DECLARE_CLASS_IN(_Name, nitf) + +#endif diff --git a/modules/c++/nitf/include/nitf/Pair.hpp b/modules/c++/nitf/include/nitf/Pair.hpp new file mode 100644 index 000000000..440c051da --- /dev/null +++ b/modules/c++/nitf/include/nitf/Pair.hpp @@ -0,0 +1,138 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_PAIR_HPP__ +#define __NITF_PAIR_HPP__ + +#include "nitf/System.hpp" +#include "nitf/NITFException.hpp" +#include "nitf/Object.hpp" +#include + +/*! + * \file Pair.hpp + * \brief Contains wrapper implementation for Pair + */ +namespace nitf +{ + +/*! + * \class Pair + * \brief The C++ wrapper for the nitf_Pair + */ +class Pair : public nitf::Object +{ +public: + ~Pair(){} + + //! Copy constructor + Pair(const Pair & x) + { + setNative(x.getNative()); + } + + //! Assignment Operator + Pair & operator=(const Pair & x) + { + if (&x != this) + setNative(x.getNative()); + return *this; + } + + //! Set native object + Pair(nitf_Pair * x) + { + setNative(x); + getNativeOrThrow(); + } + + Pair(NITF_DATA * x) + { + setNative((nitf_Pair*)x); + getNativeOrThrow(); + } + + Pair & operator=(NITF_DATA * x) + { + setNative((nitf_Pair*)x); + getNativeOrThrow(); + return *this; + } + + /*! + * Copy the key, maintain a pointer to the data + * \param key The key in the pair (is copied) + * \param data The data in the pair (not a copy) + */ + void init(const std::string& key, NITF_DATA* data) + { + nitf_Pair_init(getNative(), key.c_str(), data); + } + + /*! + * Simply calls the init method + * \param src The source Pair + */ + void copy(nitf::Pair & src) + { + nitf_Pair_copy(getNative(), src.getNative()); + } + + //! Get the key + char * getKey() const + { + return getNativeOrThrow()->key; + } + //! Set the key + void setKey(char * value) + { + getNativeOrThrow()->key = value; + } + //! Get the data + NITF_DATA * getData() const + { + return getNativeOrThrow()->data; + } + //! Set the data + void setData(NITF_DATA * value) + { + getNativeOrThrow()->data = value; + } + + //! Get the first component (key) + char * first() const + { + return getKey(); + } + //! Get the second component (data) + NITF_DATA * second() const + { + return getData(); + } + +private: + Pair(){} + nitf_Error error; +}; + +} +#endif diff --git a/modules/c++/nitf/include/nitf/PluginRegistry.hpp b/modules/c++/nitf/include/nitf/PluginRegistry.hpp new file mode 100644 index 000000000..54f1ac5c3 --- /dev/null +++ b/modules/c++/nitf/include/nitf/PluginRegistry.hpp @@ -0,0 +1,74 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_PLUGINREGISTRY_HPP__ +#define __NITF_PLUGINREGISTRY_HPP__ + +#include "nitf/System.hpp" +#include "nitf/PluginRegistry.h" +#include "nitf/NITFException.hpp" +#include + +/*! + * \file PluginRegistry.hpp + * \brief Contains wrapper implementation for PluginRegistry + */ + +namespace nitf +{ +/*! + * \class PluginRegistry + * \brief The C++ wrapper for the nitf_PluginRegistry + */ +class PluginRegistry +{ +public: + + /*! + * Load plugins from the given directory + * \param dirName The name of the directory to load + */ + static void loadDir(const std::string& dirName) throw(nitf::NITFException); + + static void loadPlugin(const std::string& path) throw(nitf::NITFException); + + /*! + * This function allows you to register your own TRE handlers. It + * will override any handlers that are currently handling the identifier. + */ + static void registerTREHandler(NITF_PLUGIN_INIT_FUNCTION init, + NITF_PLUGIN_TRE_HANDLER_FUNCTION handler) + throw(nitf::NITFException); + + static nitf_CompressionInterface* retrieveCompressionInterface( + const std::string& comp) throw(nitf::NITFException); + +private: + PluginRegistry() + { + } + ~PluginRegistry() + { + } +}; +} +#endif diff --git a/modules/c++/nitf/include/nitf/RESegment.hpp b/modules/c++/nitf/include/nitf/RESegment.hpp new file mode 100644 index 000000000..0372c06ab --- /dev/null +++ b/modules/c++/nitf/include/nitf/RESegment.hpp @@ -0,0 +1,90 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_RESEGMENT_HPP__ +#define __NITF_RESEGMENT_HPP__ + +#include "nitf/RESegment.h" +#include "nitf/RESubheader.hpp" +#include "nitf/Object.hpp" +#include + +/*! + * \file RESegment.hpp + * \brief Contains wrapper implementation for RESegment + */ + +namespace nitf +{ + +/*! + * \class RESegment + * \brief The C++ wrapper for the nitf_RESegment + */ +DECLARE_CLASS(RESegment) +{ +public: + //! Copy constructor + RESegment(const RESegment & x); + + //! Assignment Operator + RESegment & operator=(const RESegment & x); + + //! Set native object + RESegment(nitf_RESegment * x); + + //! Default Constructor + RESegment() throw(nitf::NITFException); + + RESegment(NITF_DATA * x); + + RESegment & operator=(NITF_DATA * x); + + //! Clone + nitf::RESegment clone() throw(nitf::NITFException); + + ~RESegment(); + + //! Get the subheader + nitf::RESubheader getSubheader(); + + //! Set the subheader + void setSubheader(nitf::RESubheader & value); + + //! Get the offset + nitf::Uint64 getOffset() const; + + //! Set the offset + void setOffset(nitf::Uint64 value); + + //! Get the end + nitf::Uint64 getEnd() const; + + //! Set the end + void setEnd(nitf::Uint64 value); + +private: + nitf_Error error; +}; + +} +#endif diff --git a/modules/c++/nitf/include/nitf/RESubheader.hpp b/modules/c++/nitf/include/nitf/RESubheader.hpp new file mode 100644 index 000000000..57a1c9c7e --- /dev/null +++ b/modules/c++/nitf/include/nitf/RESubheader.hpp @@ -0,0 +1,101 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_RESUBHEADER_HPP__ +#define __NITF_RESUBHEADER_HPP__ + +#include "nitf/RESubheader.h" +#include "nitf/Object.hpp" +#include "nitf/Field.hpp" +#include "nitf/FileSecurity.hpp" +#include "nitf/Extensions.hpp" +#include + +/*! + * \file RESubheader.hpp + * \brief Contains wrapper implementation for RESubheader + */ + +namespace nitf +{ + +/*! + * \class RESubheader + * \brief The C++ wrapper for the nitf_RESubheader + */ +DECLARE_CLASS(RESubheader) +{ +public: + + //! Copy constructor + RESubheader(const RESubheader & x); + + //! Assignment Operator + RESubheader & operator=(const RESubheader & x); + + //! Set native object + RESubheader(nitf_RESubheader * x); + + //! Constructor + RESubheader() throw(nitf::NITFException); + + //! Clone + nitf::RESubheader clone() throw(nitf::NITFException); + + ~RESubheader(); + + //! Get the filePartType + nitf::Field getFilePartType(); + + //! Get the typeID + nitf::Field getTypeID(); + + //! Get the version + nitf::Field getVersion(); + + //! Get the securityClass + nitf::Field getSecurityClass(); + + //! Get the securityGroup + nitf::FileSecurity getSecurityGroup(); + + //! Set the securityGroup + void setSecurityGroup(nitf::FileSecurity value); + + //! Get the subheaderFieldsLength + nitf::Field getSubheaderFieldsLength(); + + //! Get the subheaderFields + char * getSubheaderFields() const; + + //! Get the dataLength + nitf::Uint64 getDataLength() const; + + //! Set the dataLength + void setDataLength(nitf::Uint32 value); + +private: + nitf_Error error; +}; + +} +#endif diff --git a/modules/c++/nitf/include/nitf/Reader.hpp b/modules/c++/nitf/include/nitf/Reader.hpp new file mode 100644 index 000000000..5a2677b53 --- /dev/null +++ b/modules/c++/nitf/include/nitf/Reader.hpp @@ -0,0 +1,149 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_READER_HPP__ +#define __NITF_READER_HPP__ + +#include "nitf/Reader.h" +#include "nitf/IOHandle.hpp" +#include "nitf/IOInterface.hpp" +#include "nitf/Record.hpp" +#include "nitf/ImageReader.hpp" +#include "nitf/SegmentReader.hpp" +#include "nitf/Object.hpp" +#include + +/*! + * \file Reader.hpp + * \brief Contains wrapper implementation for Reader + */ + +namespace nitf +{ + +struct ReaderDestructor : public nitf::MemoryDestructor +{ + ~ReaderDestructor() + { + } + void operator()(nitf_Reader *reader); +}; + +/*! + * \class Reader + * \brief The C++ wrapper for the nitf_Reader + */ +class Reader : public nitf::Object +{ +public: + //! Copy constructor + Reader(const Reader & x); + + //! Assignment Operator + Reader & operator=(const Reader & x); + + //! Set native object + Reader(nitf_Reader * x); + + //! Default Constructor + Reader() throw(nitf::NITFException); + + ~Reader(); + + /*! + * Return the Version of the file passed in by its file name. + * Valid return values are: + * NITF_VER_20, NITF_VER_21, or NITF_VER_UNKNOWN + */ + static nitf::Version getNITFVersion(const std::string& fileName); + + /*! + * This is the preferred method for reading a NITF 2.1 file. + * \param io The IO handle + * \return A Record containing the read information + */ + nitf::Record read(nitf::IOHandle & io) throw (nitf::NITFException); + + /*! + * This is the preferred method for reading a NITF 2.1 file. + * \param io The IO handle + * \return A Record containing the read information + */ + nitf::Record readIO(nitf::IOInterface & io) throw (nitf::NITFException); + + /*! + * Get a new image reader for the segment + * \param imageSegmentNumber The image segment number + * \return An ImageReader matching the imageSegmentNumber + */ + nitf::ImageReader newImageReader(int imageSegmentNumber) + throw (nitf::NITFException); + + /*! + * Get a new image reader for the segment + * \param imageSegmentNumber The image segment number + * \param options Options for reader + * \return An ImageReader matching the imageSegmentNumber + */ + nitf::ImageReader newImageReader(int imageSegmentNumber, + const std::map& options) + throw (nitf::NITFException); + + /*! + * Get a new DE reader for the segment + * \param deSegmentNumber The DE segment number + * \return A SegmentReader matching the deSegmentNumber + */ + nitf::SegmentReader newDEReader(int deSegmentNumber) + throw (nitf::NITFException); + + /*! + * Get a new SegmentReader for the Graphic segment + * \param segmentNumber the segment Number + * \return A SegmentReader matching the segmentNumber + */ + nitf::SegmentReader newGraphicReader(int segmentNumber) + throw (nitf::NITFException); + + /*! + * Get a new SegmentReader for the Text segment + * \param segmentNumber the segment Number + * \return A SegmentReader matching the segmentNumber + */ + nitf::SegmentReader newTextReader(int segmentNumber) + throw (nitf::NITFException); + + //! Get the warningList + nitf::List getWarningList() const; + + //! Return the record + nitf::Record getRecord() const; + + //! Return the input + nitf::IOInterface getInput() const; + +private: + nitf_Error error; +}; + +} +#endif diff --git a/modules/c++/nitf/include/nitf/Record.hpp b/modules/c++/nitf/include/nitf/Record.hpp new file mode 100644 index 000000000..adae4279b --- /dev/null +++ b/modules/c++/nitf/include/nitf/Record.hpp @@ -0,0 +1,163 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_RECORD_HPP__ +#define __NITF_RECORD_HPP__ + +#include "nitf/Record.h" +#include "nitf/System.hpp" +#include "nitf/List.hpp" +#include "nitf/FileHeader.hpp" +#include "nitf/ImageSegment.hpp" +#include "nitf/GraphicSegment.hpp" +#include "nitf/LabelSegment.hpp" +#include "nitf/TextSegment.hpp" +#include "nitf/DESegment.hpp" +#include "nitf/RESegment.hpp" +#include "nitf/Object.hpp" +#include + +/*! + * \file Record.hpp + * \brief Contains wrapper implementation for Record + */ + +namespace nitf +{ + +/*! + * \class Record + * \brief The C++ wrapper for the nitf_Record + * + * The Record is a representation of the data within + * a file. It is structurally hierarchical in a manner + * that corresponds one-to-one with the components of a NITF + * file. + */ +DECLARE_CLASS(Record) +{ +public: + //! Copy constructor + Record(const Record & x); + + //! Assignment Operator + Record & operator=(const Record & x); + + //! Set native object + Record(nitf_Record * x); + + //! Default Constructor + Record(nitf::Version version = NITF_VER_21) throw(nitf::NITFException); + + //! Clone + nitf::Record clone() throw(nitf::NITFException); + + ~Record(); + + //! Returns the NITF version + nitf::Version getVersion(); + + //! Get the header + nitf::FileHeader getHeader(); + //! Set the header + void setHeader(nitf::FileHeader & value); + + nitf::Uint32 getNumImages(); + nitf::Uint32 getNumGraphics(); + nitf::Uint32 getNumLabels(); + nitf::Uint32 getNumTexts(); + nitf::Uint32 getNumDataExtensions(); + nitf::Uint32 getNumReservedExtensions(); + + //! Get the images + nitf::List getImages(); + + + //! Get the graphics + nitf::List getGraphics(); + + //! Get the labels + nitf::List getLabels(); + + //! Get the texts + nitf::List getTexts(); + + //! Get the dataExtensions + nitf::List getDataExtensions(); + + //! Get the reservedExtensions + nitf::List getReservedExtensions(); + + //! Make and return a new ImageSegment + nitf::ImageSegment newImageSegment(int index = -1); + + //! Make and return a new GraphicSegment + nitf::GraphicSegment newGraphicSegment(int index = -1); + + //! Make and return a new TextSegment + nitf::TextSegment newTextSegment(int index = -1); + + //! Make and return a new DESegment + nitf::DESegment newDataExtensionSegment(int index = -1); + + //! Remove the image segment at the given index + void removeImageSegment(nitf::Uint32 index); + + //! Remove the graphic segment at the given index + void removeGraphicSegment(nitf::Uint32 index); + + //! Remove the text segment at the given index + void removeTextSegment(nitf::Uint32 index); + + //! Remove the label segment at the given index + void removeLabelSegment(nitf::Uint32 index); + + //! Remove the DE segment at the given index + void removeDataExtensionSegment(nitf::Uint32 index); + + //! Remove the RE segment at the given index + void removeReservedExtensionSegment(nitf::Uint32 index); + + //! Move the image segment from the oldIndex to the newIndex + void moveImageSegment(nitf::Uint32 oldIndex, int newIndex = -1); + + //! Move the text segment from the oldIndex to the newIndex + void moveTextSegment(nitf::Uint32 oldIndex, int newIndex = -1); + + //! Move the graphic segment from the oldIndex to the newIndex + void moveGraphicSegment(nitf::Uint32 oldIndex, int newIndex = -1); + + //! Move the label segment from the oldIndex to the newIndex + void moveLabelSegment(nitf::Uint32 oldIndex, int newIndex = -1); + + //! Move the DE segment from the oldIndex to the newIndex + void moveDataExtensionSegment(nitf::Uint32 oldIndex, int newIndex = -1); + + //! Move the RE segment from the oldIndex to the newIndex + void moveReservedExtensionSegment(nitf::Uint32 oldIndex, int newIndex = -1); + +private: + nitf_Error error; +}; + +} +#endif diff --git a/modules/c++/nitf/include/nitf/SegmentReader.hpp b/modules/c++/nitf/include/nitf/SegmentReader.hpp new file mode 100644 index 000000000..bf4365749 --- /dev/null +++ b/modules/c++/nitf/include/nitf/SegmentReader.hpp @@ -0,0 +1,119 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_SEGMENT_READER_HPP__ +#define __NITF_SEGMENT_READER_HPP__ + +#include "nitf/SegmentReader.h" +#include "nitf/Object.hpp" +#include + +/*! + * \file SegmentReader.hpp + * \brief Contains wrapper implementation for SegmentReader + */ +namespace nitf +{ + +/*! + * \class SegmentReader + * \brief The C++ wrapper for the nitf_SegmentReader + */ +DECLARE_CLASS(SegmentReader) +{ +public: + SegmentReader() + { + } + + //! Copy constructor + SegmentReader(const SegmentReader & x); + + //! Assignment Operator + SegmentReader & operator=(const SegmentReader & x); + + //! Set native object + SegmentReader(nitf_SegmentReader * x); + + ~SegmentReader(); + + /*! + * \brief nitf_SegmentReader_read - Read segment data + * + * The nitf_SegmentReader_read function reads data from the associated segment. + * The reading of the data is serial as if a flat file were being read by an + * input stream. Except for the first argument, this function has the same + * calling sequence and behavior as IOInterface_read. + * + * \param buffer buffer to hold data + * \param count amount of data to return + */ + void read(NITF_DATA *buffer, size_t count) throw (nitf::NITFException); + + /*! + * \brief seek - Seek in segment data + * + * The nitf_SegmentReader_seek function allows the user to seek within the extension + * data. Except for the first argument, this function has the same calling + * sequence and behaivior as IOInterface_seek. The offset is relative to the top + * of the segment data. + * + * The returned value maybe tested with NITF_IO_SUCCESS() + * \param offset the seek offest + * \param whence starting at (SEEK_SET, SEEK_CUR, SEEK_END) + * \return The offset from the beginning to the current position is set. + */ + nitf::Off seek(nitf::Off offset, int whence) throw (nitf::NITFException); + + /*! + * \brief tell - Tell location in segment data + * + * The tell function allows the user to determine the current + * offset within the extension data. Except for the first argument, this + * function has the same calling sequence and behaivior as IOInterface_tell. The + * offset is relative to the top of the segment data. + * + * The returned value may be tested with NITF_IO_SUCCESS() + * + * \return The offset from the beginning to the current position is set. + */ + nitf::Off tell(); + + /*! + * \brief getSize - Determine size of the data + * + * The nitf_SegmentReader_seek function allows the user to determine the size of + * the data. Except for the first argument, this function has the same calling + * sequence and behavior as IOInterface_getSize. + * + * The returned value maybe tested with NITF_IO_SUCCESS() + * + * \return The offset from the beginning to the current position is set. + */ + nitf::Off getSize(); + +private: + nitf_Error error; +}; + +} +#endif diff --git a/modules/c++/nitf/include/nitf/SegmentSource.hpp b/modules/c++/nitf/include/nitf/SegmentSource.hpp new file mode 100644 index 000000000..a815f92ad --- /dev/null +++ b/modules/c++/nitf/include/nitf/SegmentSource.hpp @@ -0,0 +1,115 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_SEGMENTSOURCE_HPP__ +#define __NITF_SEGMENTSOURCE_HPP__ + +#include "nitf/DataSource.hpp" +#include "nitf/SegmentSource.h" +#include "nitf/SegmentReader.hpp" +#include "nitf/IOHandle.hpp" +#include "nitf/System.hpp" +#include "nitf/NITFException.hpp" +#include "nitf/Object.hpp" +#include + +/*! + * \file SegmentSource.hpp + * \brief Contains wrapper implementations for SegmentSources + */ +namespace nitf +{ + +//! SegmentSource === DataSource +typedef DataSource SegmentSource; + +/*! + * \class SegmentMemorySource + * \brief The C++ wrapper for the nitf_SegmentMemorySource. + * + * The memory source class allows us to read directly from + * a data buffer. In the event that this is a memory-mapped file, + * we will likely get a performance gain over the direct fd approach. + * + * The constructor takes in a buffer, a size, and optionally a + * sampling factor (Typically, the factor will be applied most + * times during the case of memory mapping, although it may be used + * to sample down or cut the data into pieces). + */ +class SegmentMemorySource : public SegmentSource +{ +public: + /*! + * Constructor + * \param data The memory buffer + * \param size The size of the buffer + * \param start The start offset + * \param byteSkip The amount of bytes to skip + * \param copyData Whether or not to make a copy of the data. If this is + * false, the data must outlive the memory source. + */ + SegmentMemorySource(const char* data, size_t size, nitf::Off start, + int byteSkip, bool copyData) throw (nitf::NITFException); +}; + +/*! + * \class SegmentFileSource + * \brief The C++ wrapper for the nitf_SegmentFileSource + * + * The SegmentFileSource class is a SegmentSource that comes from an open + * file descriptor or handle. Due to any number of constraints, + * we allow the creator to specify a start point, and a byte skip. + */ +class SegmentFileSource : public SegmentSource +{ +public: + /*! + * Constructor + * \param handle The handle to store + * \param start The location to seek to (as the beginning) + * \param byteSkip The number of bytes to skip + */ + SegmentFileSource(nitf::IOHandle & io, nitf::Off start, int byteSkip) + throw (nitf::NITFException); + + ~SegmentFileSource() + { + } +}; + +class SegmentReaderSource : public SegmentSource +{ +public: + /*! + * Constructor + * \param handle The handle to store + * \param start The location to seek to (as the beginning) + * \param byteSkip The number of bytes to skip + */ + SegmentReaderSource(nitf::SegmentReader reader) throw (nitf::NITFException); + + ~SegmentReaderSource() + { + } +}; +} +#endif diff --git a/modules/c++/nitf/include/nitf/SegmentWriter.hpp b/modules/c++/nitf/include/nitf/SegmentWriter.hpp new file mode 100644 index 000000000..34a2dff4f --- /dev/null +++ b/modules/c++/nitf/include/nitf/SegmentWriter.hpp @@ -0,0 +1,72 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_SEGMENT_WRITER_HPP__ +#define __NITF_SEGMENT_WRITER_HPP__ + +#include "nitf/SegmentWriter.h" +#include "nitf/Object.hpp" +#include "nitf/WriteHandler.hpp" +#include "nitf/SegmentSource.hpp" +#include + +/*! + * \file SegmentWriter.hpp + * \brief Contains wrapper implementation for SegmentWriter + */ + +namespace nitf +{ +/*! + * \class SegmentWriter + * \brief The C++ wrapper for the nitf_SegmentWriter + */ +class SegmentWriter : public WriteHandler +{ +public: + SegmentWriter() throw (nitf::NITFException); + + SegmentWriter(nitf::SegmentSource segmentSource) + throw (nitf::NITFException); + + // Set native object + SegmentWriter(nitf_SegmentWriter *x) : WriteHandler(x) + { + } + + ~SegmentWriter(); + + /*! + * Attach a segment source from which to write. + * \param segmentSource The segment source from which to write + */ + void attachSource(nitf::SegmentSource segmentSource) + throw (nitf::NITFException); + +private: + nitf_Error error; +// bool mAdopt; +// nitf::SegmentSource* mSegmentSource; +}; + +} +#endif diff --git a/modules/c++/nitf/include/nitf/SubWindow.hpp b/modules/c++/nitf/include/nitf/SubWindow.hpp new file mode 100644 index 000000000..ce55ff66a --- /dev/null +++ b/modules/c++/nitf/include/nitf/SubWindow.hpp @@ -0,0 +1,110 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_SUBWINDOW_HPP__ +#define __NITF_SUBWINDOW_HPP__ + +#include "nitf/SubWindow.h" +#include "nitf/DownSampler.hpp" +#include "nitf/Object.hpp" +#include + +/*! + * \file SubWindow.hpp + * \brief Contains wrapper implementation for SubWindow + */ +namespace nitf +{ + +/*! + * \class SubWindow + * \brief The C++ wrapper for the nitf_SubWindow + * + * This object specifies a sub-window. It is used as an + * argument to image read and write requests to specify + * the data requested. + * + * The bandList field specifies the desired bands. Bands are + * numbered starting with zero and ordered as the bands + * appear physically in the file. The user must supply + * one buffer for each requested band. Each buffer must + * have enough storage for one band of the requested subimage + * size. + * + * The DownSampler determines what downsampling (if any) is + * performed on this sub-window request. There is no default + * DownSampler. If you just want to perform pixel skipping, call + * setDownSampler() with a PixelSkip object. + */ +DECLARE_CLASS(SubWindow) +{ +public: + //! Copy constructor + SubWindow(const SubWindow & x); + + //! Assignment Operator + SubWindow & operator=(const SubWindow & x); + + //! Set native object + SubWindow(nitf_SubWindow * x); + + //! Constructor + SubWindow() throw(nitf::NITFException); + + //! Destructor + ~SubWindow(); + + nitf::Uint32 getStartRow() const; + nitf::Uint32 getNumRows() const; + nitf::Uint32 getStartCol() const; + nitf::Uint32 getNumCols() const; + nitf::Uint32 getBandList(int i); + nitf::Uint32 getNumBands() const; + + void setStartRow(nitf::Uint32 value); + void setNumRows(nitf::Uint32 value); + void setStartCol(nitf::Uint32 value); + void setNumCols(nitf::Uint32 value); + void setBandList(nitf::Uint32 * value); + void setNumBands(nitf::Uint32 value); + + /*! + * Reference a DownSampler within the SubWindow + * The SubWindow does NOT own the DownSampler + * \param downSampler The down sampler to reference + */ + void setDownSampler(nitf::DownSampler* downSampler) + throw (nitf::NITFException); + + /*! + * Return the DownSampler that is referenced by this SubWindow. + * If no DownSampler is referenced, a NITFException is thrown. + */ + nitf::DownSampler* getDownSampler() throw (nitf::NITFException); + +private: + nitf::DownSampler* mDownSampler; + nitf_Error error; +}; + +} +#endif diff --git a/modules/c++/nitf/include/nitf/System.hpp b/modules/c++/nitf/include/nitf/System.hpp new file mode 100644 index 000000000..9660fb89a --- /dev/null +++ b/modules/c++/nitf/include/nitf/System.hpp @@ -0,0 +1,52 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_SYSTEM_HPP__ +#define __NITF_SYSTEM_HPP__ + +/*! + * \file System.hpp + */ + +#include "nitf/System.h" +#include "nitf/Field.h" +#include "nitf/Types.h" + +namespace nitf +{ +typedef nitf_Uint64 Uint64; +typedef nitf_Uint32 Uint32; +typedef nitf_Uint16 Uint16; +typedef nitf_Uint8 Uint8; +typedef nitf_Int64 Int64; +typedef nitf_Int32 Int32; +typedef nitf_Int16 Int16; +typedef nitf_Int8 Int8; +typedef nitf_Off Off; +typedef nitf_Version Version; +typedef nitf_ConvType ConvType; +typedef nitf_FieldType FieldType; +typedef nitf_AccessFlags AccessFlags; +typedef nitf_CreationFlags CreationFlags; +typedef nitf_CornersType CornersType; +} +#endif diff --git a/modules/c++/nitf/include/nitf/TRE.hpp b/modules/c++/nitf/include/nitf/TRE.hpp new file mode 100644 index 000000000..b80cd3332 --- /dev/null +++ b/modules/c++/nitf/include/nitf/TRE.hpp @@ -0,0 +1,278 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_TRE_HPP__ +#define __NITF_TRE_HPP__ + +#include "nitf/TRE.h" +#include "nitf/System.hpp" +#include "nitf/Field.hpp" +#include "nitf/Pair.hpp" +#include "nitf/Object.hpp" +#include + +/*! + * \file TRE.hpp + * \brief Contains wrapper implementation for TRE + */ +namespace nitf +{ + +/*! + * \class FieldIterator + * \brief The C++ wrapper for the nitf_TREEnumerator + */ +class TREFieldIterator : public nitf::Object +{ +public: + TREFieldIterator() : mPair(NULL) + { + setNative(NULL); + } + + ~TREFieldIterator(){} + + //! Copy constructor + TREFieldIterator(const TREFieldIterator & x) + { + setNative(x.getNative()); + } + + //! Assignment Operator + TREFieldIterator & operator=(const TREFieldIterator & x) + { + if (&x != this) + { + setNative(x.getNative()); + mPair = x.mPair; + } + return *this; + } + + //! Set native object + TREFieldIterator(nitf_TREEnumerator * x) : mPair(NULL) + { + setNative(x); + getNativeOrThrow(); + increment(); + } + + TREFieldIterator(NITF_DATA * x) + { + setNative((nitf_TREEnumerator*)x); + getNativeOrThrow(); + increment(); + } + + TREFieldIterator & operator=(NITF_DATA * x) + { + setNative((nitf_TREEnumerator*)x); + getNativeOrThrow(); + increment(); + return *this; + } + + /*! + * Checks to see if this iterator is equal to another + * \param it2 The iterator to compare with + * \return True if so, and False otherwise + */ + bool operator==(const nitf::TREFieldIterator& it2) + { + //need to do this double-check so that the last iteration of an iterator + //doesn't get skipped + if (getNative() == it2.getNative()) + return mPair == it2.mPair; + return false; + } + + bool operator!=(const nitf::TREFieldIterator& it2) + { + return !this->operator==((nitf::TREFieldIterator&)it2); + } + + /*! + * Increment the iterator + */ + void increment() + { + nitf_TREEnumerator* enumerator = getNative(); + if (isValid() && enumerator->hasNext(&enumerator)) + mPair = enumerator->next(enumerator, &error); + else + mPair = NULL; + setNative(enumerator); //always reset, in case it got destroyed + } + + //! Increment the iterator (postfix) + void operator++(int ) + { + increment(); + } + + //! Increment the iterator (prefix) + void operator++() + { + increment(); + } + + //! Get the TRE from the iterator + nitf::Pair operator*() + { + if (!mPair) + throw except::NullPointerReference(); + return nitf::Pair(mPair); + } + + std::string getFieldDescription() + { + nitf_TREEnumerator* enumerator = getNative(); + if (enumerator && isValid()) + { + const char* desc = enumerator->getFieldDescription(enumerator, + &error); + if (desc) + return std::string(desc); + } + return ""; + } + +private: + nitf_Error error; + nitf_Pair *mPair; +}; + + + +/*! + * \class TRE + * \brief The C++ wrapper for the nitf_TRE + */ +DECLARE_CLASS(TRE) +{ +public: + +typedef nitf::TREFieldIterator Iterator; + + //! Copy constructor + TRE(const TRE & x); + + //! Assignment Operator + TRE & operator=(const TRE & x); + + //! Set native object + TRE(nitf_TRE * x); + + TRE(NITF_DATA * x); + + TRE & operator=(NITF_DATA * x); + + //! Without the const char* constructors, in VS if you do something like + // TRE("my_tre_tag") + // You get the NITF_DATA* constructor rather than the std::string one + TRE(const char* tag) throw(nitf::NITFException); + + TRE(const char* tag, const char* id) throw(nitf::NITFException); + + TRE(const std::string& tag) throw(nitf::NITFException); + + TRE(const std::string& tag, const std::string& id) + throw(nitf::NITFException); + + //! Clone + nitf::TRE clone() throw(nitf::NITFException); + + ~TRE(); + + /*! + * Get a begin TRE field iterator + * \return A field iterator pointing at the first field in the TRE + */ + Iterator begin(); + + /*! + * Get an end TRE field iterator + * \return A field iterator pointing PAST the last field in the TRE + */ + Iterator end() throw (nitf::NITFException); + + /*! + * Get the field specified by the key. Throws an exception if the field + * does not exist. + */ + nitf::Field getField(const std::string& key) + throw(except::NoSuchKeyException); + + nitf::Field operator[] (const std::string& key) + throw(except::NoSuchKeyException); + + /*! + * Returns a List of Fields that match the given pattern. + */ + nitf::List find(const std::string& pattern); + + /*! + * Sets the field with the given value. The input value + * is converted to a std::string, and the string-ized value + * is then used as the value input for the TRE field. + */ + template void setField(std::string key, T value) + { + std::string s = str::toString(value); + if (!nitf_TRE_setField(getNative(), + key.c_str(), + (NITF_DATA*)s.c_str(), + s.size(), + &error) ) + throw nitf::NITFException(&error); + } + + /*! + * Does the field exist? + * \param key The field name in which to check + */ + bool exists(const std::string& key); + + //! Get the total length of the TRE data + size_t getCurrentSize(); + + //! Get the tag + std::string getTag() const; + + //! Set the tag + void setTag(const std::string & value); + + /** + * Get the TRE identifier. This is NOT the tag, however it may be the + * same value as the tag. The ID is used to identify a specific + * version/incarnation of the TRE, if multiple are possible. For most TREs, + * this value will be the same as the tag. + */ + std::string getID() const; + + +private: + nitf_Error error; +}; + +} +#endif diff --git a/modules/c++/nitf/include/nitf/TextSegment.hpp b/modules/c++/nitf/include/nitf/TextSegment.hpp new file mode 100644 index 000000000..fbba36619 --- /dev/null +++ b/modules/c++/nitf/include/nitf/TextSegment.hpp @@ -0,0 +1,92 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_TEXTSEGMENT_HPP__ +#define __NITF_TEXTSEGMENT_HPP__ + +#include "nitf/TextSegment.h" +#include "nitf/System.hpp" +#include "nitf/NITFException.hpp" +#include "nitf/TextSubheader.hpp" +#include "nitf/Object.hpp" +#include + +/*! + * \file TextSegment.hpp + * \brief Contains wrapper implementation for TextSegment + */ + +namespace nitf +{ + +/*! + * \class TextSegment + * \brief The C++ wrapper for the nitf_TextSegment + */ +DECLARE_CLASS(TextSegment) +{ +public: + //! Copy constructor + TextSegment(const TextSegment & x); + + //! Assignment Operator + TextSegment & operator=(const TextSegment & x); + + //! Set native object + TextSegment(nitf_TextSegment * x); + + //! Constructor + TextSegment() throw(nitf::NITFException); + + TextSegment(NITF_DATA * x); + + TextSegment & operator=(NITF_DATA * x); + + //! Clone + nitf::TextSegment clone() throw(nitf::NITFException); + + ~TextSegment(); + + //! Get the subheader + nitf::TextSubheader getSubheader(); + + //! Set the subheader + void setSubheader(nitf::TextSubheader & value); + + //! Get the offset + nitf::Uint64 getOffset() const; + + //! Set the offset + void setOffset(nitf::Uint64 value); + + //! Get the end + nitf::Uint64 getEnd() const; + + //! Set the end + void setEnd(nitf::Uint64 value); + +private: + nitf_Error error; +}; + +} +#endif diff --git a/modules/c++/nitf/include/nitf/TextSubheader.hpp b/modules/c++/nitf/include/nitf/TextSubheader.hpp new file mode 100644 index 000000000..f6e903118 --- /dev/null +++ b/modules/c++/nitf/include/nitf/TextSubheader.hpp @@ -0,0 +1,113 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_TEXTSUBHEADER_HPP__ +#define __NITF_TEXTSUBHEADER_HPP__ + +#include "nitf/TextSubheader.h" +#include "nitf/NITFException.hpp" +#include "nitf/Object.hpp" +#include "nitf/FileSecurity.hpp" +#include "nitf/Extensions.hpp" +#include + +/*! + * \file TextSubheader.hpp + * \brief Contains wrapper implementation for TextSubheader + */ + +namespace nitf +{ + +/*! + * \class TextSubheader + * \brief The C++ wrapper for the nitf_TextSubheader + */ +DECLARE_CLASS(TextSubheader) +{ +public: + + //! Copy constructor + TextSubheader(const TextSubheader & x); + + //! Assignment Operator + TextSubheader & operator=(const TextSubheader & x); + + //! Set native object + TextSubheader(nitf_TextSubheader * x); + + //! Default Constructor + TextSubheader() throw(nitf::NITFException); + + //! Clone + nitf::TextSubheader clone() throw(nitf::NITFException); + + ~TextSubheader(); + + //! Get the filePartType + nitf::Field getFilePartType(); + + //! Get the textID + nitf::Field getTextID(); + + //! Get the attachmentLevel + nitf::Field getAttachmentLevel(); + + //! Get the dateTime + nitf::Field getDateTime(); + + //! Get the title + nitf::Field getTitle(); + + //! Get the securityClass + nitf::Field getSecurityClass(); + + //! Get the securityGroup + nitf::FileSecurity getSecurityGroup(); + + //! Set the securityGroup + void setSecurityGroup(nitf::FileSecurity value); + + //! Get the encrypted + nitf::Field getEncrypted(); + + //! Get the format + nitf::Field getFormat(); + + //! Get the extendedHeaderLength + nitf::Field getExtendedHeaderLength(); + + //! Get the extendedHeaderOverflow + nitf::Field getExtendedHeaderOverflow(); + + //! Get the extendedSection + nitf::Extensions getExtendedSection(); + + //! Set the extendedSection + void setExtendedSection(nitf::Extensions value); + +private: + nitf_Error error; +}; + +} +#endif diff --git a/modules/c++/nitf/include/nitf/Utils.hpp b/modules/c++/nitf/include/nitf/Utils.hpp new file mode 100644 index 000000000..570051677 --- /dev/null +++ b/modules/c++/nitf/include/nitf/Utils.hpp @@ -0,0 +1,48 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __NITF_UTILS_HPP__ +#define __NITF_UTILS_HPP__ + +#include "nitf/System.hpp" +#include + +namespace nitf +{ +struct Utils +{ + static bool isNumeric(std::string str); + + static bool isAlpha(std::string str); + + static void decimalToGeographic(double decimal, int* degrees, int* minutes, + double* seconds); + + static double geographicToDecimal(int degrees, int minutes, double seconds); + + static char cornersTypeAsCoordRep(nitf::CornersType type); + +}; + +} + +#endif diff --git a/modules/c++/nitf/include/nitf/WriteHandler.hpp b/modules/c++/nitf/include/nitf/WriteHandler.hpp new file mode 100644 index 000000000..6ecf2a000 --- /dev/null +++ b/modules/c++/nitf/include/nitf/WriteHandler.hpp @@ -0,0 +1,107 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_WRITE_HANDLER_HPP__ +#define __NITF_WRITE_HANDLER_HPP__ + +#include "nitf/System.hpp" +#include "nitf/StreamIOWriteHandler.h" +#include "nitf/Object.hpp" +#include "nitf/IOInterface.hpp" +#include + +/*! + * \file WriteHandler.hpp + * \brief Contains wrapper implementations for WriteHandlers + */ +namespace nitf +{ + +/*! + * \class WriteHandler + * \brief The C++ wrapper for the nitf_WriteHandler + * + * All WriteHandlers are treated as pointers in the nitf system. + */ +DECLARE_CLASS(WriteHandler) +{ +public: + + //! Copy constructor + WriteHandler(const WriteHandler & x) + { + setNative(x.getNative()); + } + + //! Assignment Operator + WriteHandler & operator=(const WriteHandler & x) + { + if (&x != this) + setNative(x.getNative()); + return *this; + } + + // Set native object + WriteHandler(nitf_WriteHandler *x) + { + setNative(x); + getNativeOrThrow(); + } + + //! Destructor + virtual ~WriteHandler() + { + } + + /*! + * Write to the given output IOInterface + * \param handle the output IOInterface + */ + virtual void write(IOInterface& handle) throw (nitf::NITFException); + +protected: + //! Constructor + WriteHandler() + { + } + + nitf_Error error; +}; + + +/*! + * \class StreamIOWriteHandler + * \brief Write handler that streams from an input source. + */ +class StreamIOWriteHandler : public WriteHandler +{ +public: + //! Constructor + StreamIOWriteHandler(IOInterface& sourceHandle, nitf::Uint64 offset, + nitf::Uint64 bytes); + ~StreamIOWriteHandler() + { + } +}; + +} +#endif diff --git a/modules/c++/nitf/include/nitf/Writer.hpp b/modules/c++/nitf/include/nitf/Writer.hpp new file mode 100644 index 000000000..4e5f0d9b0 --- /dev/null +++ b/modules/c++/nitf/include/nitf/Writer.hpp @@ -0,0 +1,173 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_WRITER_HPP__ +#define __NITF_WRITER_HPP__ + +#include +#include "nitf/Writer.h" +#include "nitf/List.hpp" +#include "nitf/NITFException.hpp" +#include "nitf/IOHandle.hpp" +#include "nitf/IOInterface.hpp" +#include "nitf/Record.hpp" +#include "nitf/ImageWriter.hpp" +#include "nitf/SegmentWriter.hpp" +#include "nitf/Object.hpp" +#include + +/*! + * \file Writer.hpp + * \brief Contains wrapper implementation for Writer + */ + +namespace nitf +{ + +struct WriterDestructor : public nitf::MemoryDestructor +{ + ~WriterDestructor() + { + } + void operator()(nitf_Writer *writer); +}; + +/*! + * \class Writer + * \brief The C++ wrapper for the nitf_Writer + */ +class Writer : public nitf::Object +{ +public: + //! Copy constructor + Writer(const Writer & x); + + //! Assignment Operator + Writer & operator=(const Writer & x); + + //! Set native object + Writer(nitf_Writer * x); + + //! Constructor + Writer() throw (nitf::NITFException); + + ~Writer(); + + //! Write the record to disk + void write(); + + /*! + * Prepare the writer + * \param io The IO handle to use + * \param record The record to write out + */ + void prepare(nitf::IOHandle & io, nitf::Record & record) + throw (nitf::NITFException); + + /*! + * Prepare the writer + * \param io The IO handle to use + * \param record The record to write out + */ + void prepareIO(nitf::IOInterface & io, nitf::Record & record) + throw (nitf::NITFException); + + /*! + * Sets the WriteHandler for the Image at the given index. + */ + void setImageWriteHandler(int index, + mem::SharedPtr writeHandler) + throw (nitf::NITFException); + + /*! + * Sets the WriteHandler for the Graphic at the given index. + */ + void setGraphicWriteHandler(int index, + mem::SharedPtr writeHandler) + throw (nitf::NITFException); + + /*! + * Sets the WriteHandler for the Text at the given index. + */ + void setTextWriteHandler(int index, + mem::SharedPtr writeHandler) + throw (nitf::NITFException); + + /*! + * Sets the WriteHandler for the DE Segment at the given index. + */ + void setDEWriteHandler(int index, + mem::SharedPtr writeHandler) + throw (nitf::NITFException); + + /** + * Returns a NEW ImageWriter for the given index + * + * The pointer is deleted by the library, so don't delete it yourself. + */ + nitf::ImageWriter newImageWriter(int imageNumber) + throw (nitf::NITFException); + + /** + * Returns a NEW ImageWriter for the given index + * + * The pointer is deleted by the library, so don't delete it yourself. + */ + nitf::ImageWriter newImageWriter(int imageNumber, + const std::map& options) + throw (nitf::NITFException); + + /** + * Returns a NEW SegmentWriter for the given index + * + * The pointer is deleted by the library, so don't delete it yourself. + */ + nitf::SegmentWriter newGraphicWriter(int graphicNumber) + throw (nitf::NITFException); + + /** + * Returns a NEW SegmentWriter for the given index + * + * The pointer is deleted by the library, so don't delete it yourself. + */ + nitf::SegmentWriter newTextWriter(int textNumber) + throw (nitf::NITFException); + + /** + * Returns a NEW SegmentWriter for the given index + * + * The pointer is deleted by the library, so don't delete it yourself. + */ + nitf::SegmentWriter newDEWriter(int deNumber) throw (nitf::NITFException); + + //! Get the warningList + nitf::List getWarningList(); + +private: + nitf_Error error; + + //! c++ write handlers need to be kept in scope + std::vector > mWriteHandlers; +}; + +} +#endif diff --git a/modules/c++/nitf/include/nitf/WriterOptions.hpp b/modules/c++/nitf/include/nitf/WriterOptions.hpp new file mode 100644 index 000000000..5b8d76327 --- /dev/null +++ b/modules/c++/nitf/include/nitf/WriterOptions.hpp @@ -0,0 +1,29 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2013, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_WRITER_OPTIONS_HPP__ +#define __NITF_WRITER_OPTIONS_HPP__ + +#include "nitf/WriterOptions.h" + +#endif + diff --git a/modules/c++/nitf/source/BandInfo.cpp b/modules/c++/nitf/source/BandInfo.cpp new file mode 100644 index 000000000..4900b769f --- /dev/null +++ b/modules/c++/nitf/source/BandInfo.cpp @@ -0,0 +1,147 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/BandInfo.hpp" + +using namespace nitf; + +BandInfo::BandInfo(const BandInfo & x) +{ + setNative(x.getNative()); +} + +BandInfo & BandInfo::operator=(const BandInfo & x) +{ + if (&x != this) + setNative(x.getNative()); + return *this; +} + +BandInfo::BandInfo(nitf_BandInfo * x) +{ + setNative(x); + getNativeOrThrow(); +} + +BandInfo::BandInfo() +{ + setNative(nitf_BandInfo_construct(&error)); + getNativeOrThrow(); + setManaged(false); +} + +BandInfo::~BandInfo() {} + +nitf::Field BandInfo::getRepresentation() +{ + return nitf::Field(getNativeOrThrow()->representation); +} + +nitf::Field BandInfo::getSubcategory() +{ + return nitf::Field(getNativeOrThrow()->subcategory); +} + +nitf::Field BandInfo::getImageFilterCondition() +{ + return nitf::Field(getNativeOrThrow()->imageFilterCondition); +} + +nitf::Field BandInfo::getImageFilterCode() +{ + return nitf::Field(getNativeOrThrow()->imageFilterCode); +} + +nitf::Field BandInfo::getNumLUTs() +{ + return nitf::Field(getNativeOrThrow()->numLUTs); +} + +nitf::Field BandInfo::getBandEntriesPerLUT() +{ + return nitf::Field(getNativeOrThrow()->bandEntriesPerLUT); +} + +nitf::LookupTable BandInfo::getLookupTable() +{ + if (!getNativeOrThrow()->lut) + { + //we'll create one - there's no harm in doing it + getNativeOrThrow()->lut = nitf_LookupTable_construct(0, 0, &error); + if (!getNativeOrThrow()->lut) + throw nitf::NITFException(&error); + } + return nitf::LookupTable(getNativeOrThrow()->lut); +} + +void BandInfo::init(const std::string& representation, + const std::string& subcategory, + const std::string& imageFilterCondition, + const std::string& imageFilterCode, + nitf::Uint32 numLUTs, + nitf::Uint32 bandEntriesPerLUT, + nitf::LookupTable& lut) throw(nitf::NITFException) +{ + if (getNativeOrThrow()->lut) + { + //release the owned lut + nitf::LookupTable oldLut = nitf::LookupTable(getNativeOrThrow()->lut); + oldLut.setManaged(false); + } + + if (!nitf_BandInfo_init(getNativeOrThrow(), + representation.c_str(), + subcategory.c_str(), + imageFilterCondition.c_str(), + imageFilterCode.c_str(), + numLUTs, + bandEntriesPerLUT, + lut.getNative() ? lut.getNative() : NULL, + &error)) + throw nitf::NITFException(&error); + + + //have the library manage the new lut + lut.setManaged(true); +} + +void BandInfo::init(const std::string& representation, + const std::string& subcategory, + const std::string& imageFilterCondition, + const std::string& imageFilterCode) throw(nitf::NITFException) +{ + if (getNativeOrThrow()->lut) + { + //release the owned lut + nitf::LookupTable oldLut = nitf::LookupTable(getNativeOrThrow()->lut); + oldLut.setManaged(false); + } + + if (!nitf_BandInfo_init(getNativeOrThrow(), + representation.c_str(), + subcategory.c_str(), + imageFilterCondition.c_str(), + imageFilterCode.c_str(), + 0, 0, NULL, &error)) + throw nitf::NITFException(&error); +} + diff --git a/modules/c++/nitf/source/BandSource.cpp b/modules/c++/nitf/source/BandSource.cpp new file mode 100644 index 000000000..e85c5366b --- /dev/null +++ b/modules/c++/nitf/source/BandSource.cpp @@ -0,0 +1,181 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/BandSource.hpp" + +nitf::MemorySource::MemorySource(char * data, + size_t size, + nitf::Off start, + int numBytesPerPixel, + int pixelSkip) throw(nitf::NITFException) +{ + setNative(nitf_MemorySource_construct(data, size, start, numBytesPerPixel, pixelSkip, &error)); + setManaged(false); +} + +nitf::FileSource::FileSource(nitf::IOHandle & io, + nitf::Off start, + int numBytesPerPixel, + int pixelSkip) throw(nitf::NITFException) +{ + setNative(nitf_IOSource_construct(io.getNative(), start, numBytesPerPixel, pixelSkip, &error)); + setManaged(false); + io.setManaged(true); //TODO must release this on destruction +} + +nitf::FileSource::FileSource(const std::string& fname, + nitf::Off start, + int numBytesPerPixel, + int pixelSkip) throw (nitf::NITFException) +{ + setNative(nitf_FileSource_constructFile(fname.c_str(), + start, + numBytesPerPixel, + pixelSkip, & error)); + setManaged(false); +} + +nitf::RowSource::RowSource( + nitf::Uint32 band, + nitf::Uint32 numRows, + nitf::Uint32 numCols, + nitf::Uint32 pixelSize, + nitf::RowSourceCallback *callback) throw(nitf::NITFException) + : mBand(band), + mNumRows(numRows), + mNumCols(numCols), + mPixelSize(pixelSize) +{ + setNative(nitf_RowSource_construct(callback, + &RowSource::nextRow, + mBand, + mNumRows, + mNumCols * mPixelSize, + &error)); + setManaged(false); +} + +NITF_BOOL nitf::RowSource::nextRow(void* algorithm, + nitf_Uint32 band, + NITF_DATA* buffer, + nitf_Error* error) +{ + nitf::RowSourceCallback* const callback = + reinterpret_cast(algorithm); + if (!callback) + { + nitf_Error_init(error, "Null pointer reference", + NITF_CTXT, NITF_ERR_INVALID_OBJECT); + return NITF_FAILURE; + } + + try + { + callback->nextRow(band, (char*)buffer); + } + catch (const except::Exception &ex) + { + nitf_Error_initf(error, + NITF_CTXT, + NITF_ERR_READING_FROM_FILE, + ex.getMessage().c_str()); + return NITF_FAILURE; + } + catch (const std::exception &ex) + { + nitf_Error_initf(error, + NITF_CTXT, + NITF_ERR_READING_FROM_FILE, + ex.what()); + return NITF_FAILURE; + } + catch (...) + { + nitf_Error_initf(error, + NITF_CTXT, + NITF_ERR_READING_FROM_FILE, + "Unknown exception"); + return NITF_FAILURE; + } + + return NITF_SUCCESS; +} + +nitf::DirectBlockSource::DirectBlockSource(nitf::ImageReader& imageReader, nitf::Uint32 numBands) + throw(nitf::NITFException) +{ + setNative(nitf_DirectBlockSource_construct(this, + &DirectBlockSource::nextBlock, + imageReader.getNative(), + numBands, &error)); + setManaged(false); +} + +NITF_BOOL nitf::DirectBlockSource::nextBlock(void *callback, + char * buf, + nitf_Uint8 * block, + nitf_Uint32 blockNumber, + nitf_Uint64 blockSize, + nitf_Error * error) +{ + nitf::DirectBlockSource* const cb = + reinterpret_cast(callback); + if (!callback) + { + nitf_Error_init(error, "Null pointer reference", + NITF_CTXT, NITF_ERR_INVALID_OBJECT); + return NITF_FAILURE; + } + + try + { + cb->nextBlock(buf, block, blockNumber, blockSize); + } + catch (const except::Exception &ex) + { + nitf_Error_initf(error, + NITF_CTXT, + NITF_ERR_READING_FROM_FILE, + ex.getMessage().c_str()); + return NITF_FAILURE; + } + catch (const std::exception &ex) + { + nitf_Error_initf(error, + NITF_CTXT, + NITF_ERR_READING_FROM_FILE, + ex.what()); + return NITF_FAILURE; + } + catch (...) + { + nitf_Error_initf(error, + NITF_CTXT, + NITF_ERR_READING_FROM_FILE, + "Unknown exception"); + return NITF_FAILURE; + } + + return NITF_SUCCESS; +} + + diff --git a/modules/c++/nitf/source/BlockingInfo.cpp b/modules/c++/nitf/source/BlockingInfo.cpp new file mode 100644 index 000000000..8923af078 --- /dev/null +++ b/modules/c++/nitf/source/BlockingInfo.cpp @@ -0,0 +1,108 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/BlockingInfo.hpp" + +using namespace nitf; + +BlockingInfo::BlockingInfo(const BlockingInfo & x) +{ + setNative(x.getNative()); +} + +BlockingInfo & BlockingInfo::operator=(const BlockingInfo & x) +{ + if (&x != this) + setNative(x.getNative()); + return *this; +} + +BlockingInfo::BlockingInfo(nitf_BlockingInfo * x) +{ + setNative(x); + getNativeOrThrow(); +} + +BlockingInfo::BlockingInfo() +{ + setNative(nitf_BlockingInfo_construct(&error)); + getNativeOrThrow(); + setManaged(false); +} + +BlockingInfo::~BlockingInfo(){} + + +nitf::Uint32 BlockingInfo::getNumBlocksPerRow() const +{ + return getNativeOrThrow()->numBlocksPerRow; +} + +void BlockingInfo::setNumBlocksPerRow(nitf::Uint32 value) +{ + getNativeOrThrow()->numBlocksPerRow = value; +} + +nitf::Uint32 BlockingInfo::getNumBlocksPerCol() const +{ + return getNativeOrThrow()->numBlocksPerCol; +} + +void BlockingInfo::setNumBlocksPerCol(nitf::Uint32 value) +{ + getNativeOrThrow()->numBlocksPerCol = value; +} + +nitf::Uint32 BlockingInfo::getNumRowsPerBlock() const +{ + return getNativeOrThrow()->numRowsPerBlock; +} + +void BlockingInfo::setNumRowsPerBlock(nitf::Uint32 value) +{ + getNativeOrThrow()->numRowsPerBlock = value; +} + +nitf::Uint32 BlockingInfo::getNumColsPerBlock() const +{ + return getNativeOrThrow()->numColsPerBlock; +} + +void BlockingInfo::setNumColsPerBlock(nitf::Uint32 value) +{ + getNativeOrThrow()->numColsPerBlock = value; +} + +size_t BlockingInfo::getLength() const +{ + return getNativeOrThrow()->length; +} + +void BlockingInfo::setLength(size_t value) +{ + getNativeOrThrow()->length = value; +} + +void BlockingInfo::print(FILE *file) +{ + nitf_BlockingInfo_print(getNativeOrThrow(), file); +} diff --git a/modules/c++/nitf/source/BufferedWriter.cpp b/modules/c++/nitf/source/BufferedWriter.cpp new file mode 100644 index 000000000..80cea31aa --- /dev/null +++ b/modules/c++/nitf/source/BufferedWriter.cpp @@ -0,0 +1,179 @@ +#include + +#include "nitf/BufferedWriter.hpp" + +namespace nitf +{ +BufferedWriter::BufferedWriter(const std::string& file, size_t bufferSize) : + mBufferSize(bufferSize), + mScopedBuffer(new char[bufferSize]), + mBuffer(mScopedBuffer.get()), + mPosition(0), + mTotalWritten(0), + mBlocksWritten(0), + mPartialBlocks(0), + mElapsedTime(0), + mFile(file, sys::File::WRITE_ONLY, sys::File::CREATE | sys::File::TRUNCATE) +{ + if (mBufferSize == 0) + { + throw except::Exception(Ctxt( + "BufferedWriters must have a buffer size greater than zero")); + } +} + +BufferedWriter::BufferedWriter(const std::string& file, + char* buffer, + size_t size, + bool adopt) : + mBufferSize(size), + mScopedBuffer(adopt ? buffer : NULL), + mBuffer(buffer), + mPosition(0), + mTotalWritten(0), + mBlocksWritten(0), + mPartialBlocks(0), + mElapsedTime(0), + mFile(file, sys::File::WRITE_ONLY, sys::File::CREATE) +{ + if (mBufferSize == 0) + { + throw except::Exception(Ctxt( + "BufferedWriters must have a buffer size greater than zero")); + } +} + +BufferedWriter::~BufferedWriter() +{ + try + { + if (mFile.isOpen()) + { + // If the file is still open, we may not have flushed out our + // internal buffer. Note that we can't just call closeImpl() + // here because it's virtual. sys::File's destructor will take + // care of closing the file but wouldn't flush (i.e. fsync()) so + // we call this too. + flushBuffer(); + mFile.flush(); + } + } + catch (...) + { + } +} + +void BufferedWriter::flushBuffer() +{ + flushBuffer(mBuffer); +} + +void BufferedWriter::flushBuffer(const char* buf) +{ + if (mPosition > 0) + { + sys::RealTimeStopWatch sw; + sw.start(); + mFile.writeFrom(buf, mPosition); + mElapsedTime += (sw.stop() / 1000.); + + mTotalWritten += mPosition; + + ++mBlocksWritten; + + if (mPosition != mBufferSize) + { + ++mPartialBlocks; + } + + mPosition = 0; + } +} + +void BufferedWriter::readImpl(char* , size_t ) +{ + throw except::Exception( + Ctxt("We cannot do reads on a write-only handle")); +} + +void BufferedWriter::writeImpl(const char* buf, size_t size) +{ + size_t from = 0; + while (size > 0) + { + size_t bytes = size; + + if ((mPosition + size) > mBufferSize) + { + // We will be flushing the buffer + // write as many bytes as we can + bytes = mBufferSize - mPosition; + } + + // copy bytes to internal buffer + if (bytes < mBufferSize) + { + // Copy over and subtract bytes from the size left + memcpy(mBuffer + mPosition, buf + from, bytes); + + // update counters + mPosition += bytes; + size -= bytes; + from += bytes; + + // check the internal buffer + if (mPosition == mBufferSize) + { + flushBuffer(); + } + } + // flush using the input buffer directly + else + { + // update mPosition before the flush + mPosition += bytes; + flushBuffer(buf + from); + + // update counters + size -= bytes; + from += bytes; + } + } +} + +bool BufferedWriter::canSeekImpl() const +{ + return true; +} + +nitf::Off BufferedWriter::seekImpl(nitf::Off offset, int whence) +{ + // This is very unfortunate, since it creates a partial block + flushBuffer(); + + return mFile.seekTo(offset, whence); +} + +nitf::Off BufferedWriter::tellImpl() const +{ + return (mFile.getCurrentOffset() + mPosition); +} + +nitf::Off BufferedWriter::getSizeImpl() const +{ + return (mFile.length() + mPosition); +} + +int BufferedWriter::getModeImpl() const +{ + return NITF_ACCESS_WRITEONLY; +} + +void BufferedWriter::closeImpl() +{ + // flush everything first + flushBuffer(); + mFile.flush(); + mFile.close(); +} +} diff --git a/modules/c++/nitf/source/ComponentInfo.cpp b/modules/c++/nitf/source/ComponentInfo.cpp new file mode 100644 index 000000000..73cef0c19 --- /dev/null +++ b/modules/c++/nitf/source/ComponentInfo.cpp @@ -0,0 +1,70 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/ComponentInfo.hpp" + +using namespace nitf; + +ComponentInfo::ComponentInfo(const ComponentInfo & x) +{ + setNative(x.getNative()); +} + +ComponentInfo & ComponentInfo::operator=(const ComponentInfo & x) +{ + if (&x != this) + setNative(x.getNative()); + return *this; +} + +ComponentInfo::ComponentInfo(nitf_ComponentInfo * x) +{ + setNative(x); + getNativeOrThrow(); +} + +ComponentInfo::ComponentInfo(nitf::Uint32 subHeaderSize, nitf::Uint64 dataSize) + throw(nitf::NITFException) +{ + setNative(nitf_ComponentInfo_construct(subHeaderSize, dataSize, &error)); + getNativeOrThrow(); + setManaged(false); +} + +ComponentInfo ComponentInfo::clone() throw(nitf::NITFException) +{ + nitf::ComponentInfo dolly(nitf_ComponentInfo_clone(getNativeOrThrow(), &error)); + dolly.setManaged(false); + return dolly; +} + +ComponentInfo::~ComponentInfo(){} + +nitf::Field ComponentInfo::getLengthSubheader() +{ + return nitf::Field(getNativeOrThrow()->lengthSubheader); +} + +nitf::Field ComponentInfo::getLengthData() +{ + return nitf::Field(getNativeOrThrow()->lengthData); +} diff --git a/modules/c++/nitf/source/CompressionInterface.cpp b/modules/c++/nitf/source/CompressionInterface.cpp new file mode 100644 index 000000000..8df244ae2 --- /dev/null +++ b/modules/c++/nitf/source/CompressionInterface.cpp @@ -0,0 +1,141 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + +using namespace nitf; + +NITF_BOOL CompressionInterface::adapterStart( + nitf_CompressionControl* object, + nitf_Uint64 offset, + nitf_Uint64 dataLength, + nitf_Uint64* blockMask, + nitf_Uint64* padMask, + nitf_Error* error) +{ + try + { + reinterpret_cast(object)->start(offset, + dataLength, + blockMask, + padMask); + return NRT_SUCCESS; + } + catch (const except::Exception& ex) + { + nrt_Error_init(error, ex.getMessage().c_str(), NRT_CTXT, + NRT_ERR_COMPRESSION); + return NRT_FAILURE; + } + catch (const std::exception& ex) + { + nrt_Error_init(error, ex.what(), NRT_CTXT, + NRT_ERR_COMPRESSION); + return NRT_FAILURE; + } + catch (...) + { + nrt_Error_init(error, "Unknown error", NRT_CTXT, + NRT_ERR_COMPRESSION); + return NRT_FAILURE; + } +} + +NITF_BOOL CompressionInterface::adapterWriteBlock( + nitf_CompressionControl* object, + nitf_IOInterface* io, + const nitf_Uint8* data, + NITF_BOOL pad, + NITF_BOOL noData, + nitf_Error* error) +{ + try + { + nitf::IOInterface ioInter(io); + ioInter.setManaged(true); + reinterpret_cast(object)->writeBlock(ioInter, + data, + pad, + noData); + return NRT_SUCCESS; + } + catch (const except::Exception& ex) + { + nrt_Error_init(error, ex.getMessage().c_str(), NRT_CTXT, + NRT_ERR_COMPRESSION); + return NRT_FAILURE; + } + catch (const std::exception& ex) + { + nrt_Error_init(error, ex.what(), NRT_CTXT, + NRT_ERR_COMPRESSION); + return NRT_FAILURE; + } + catch (...) + { + nrt_Error_init(error, "Unknown error", NRT_CTXT, + NRT_ERR_COMPRESSION); + return NRT_FAILURE; + } +} + +NITF_BOOL CompressionInterface::adapterEnd( + nitf_CompressionControl* object, + nitf_IOInterface* io, + nitf_Error* error) +{ + try + { + nitf::IOInterface ioInter(io); + ioInter.setManaged(true); + reinterpret_cast(object)->end(ioInter); + return NRT_SUCCESS; + } + catch (const except::Exception& ex) + { + nrt_Error_init(error, ex.getMessage().c_str(), NRT_CTXT, + NRT_ERR_COMPRESSION); + return NRT_FAILURE; + } + catch (const std::exception& ex) + { + nrt_Error_init(error, ex.what(), NRT_CTXT, + NRT_ERR_COMPRESSION); + return NRT_FAILURE; + } + catch (...) + { + nrt_Error_init(error, "Unknown error", NRT_CTXT, + NRT_ERR_COMPRESSION); + return NRT_FAILURE; + } +} + +void CompressionInterface::adapterDestroy( + nitf_CompressionControl** object) +{ + if (object != NULL && *object != NULL) + { + delete reinterpret_cast(*object); + *object = NULL; + } +} diff --git a/modules/c++/nitf/source/CustomIO.cpp b/modules/c++/nitf/source/CustomIO.cpp new file mode 100644 index 000000000..7da2e1c7c --- /dev/null +++ b/modules/c++/nitf/source/CustomIO.cpp @@ -0,0 +1,316 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include +#include + +namespace nitf +{ +CustomIO::CustomIO() : + IOInterface(createInterface(this)) +{ + setManaged(false); +} + +CustomIO::~CustomIO() +{ + // This is messy but I don't think there's a cleaner way to do this. + // After this destructor fires, IOInterface's destructor will fire which + // will eventually call IOInterfaceDestructor::operator() which will + // in turn try to call nitf_IOInterface_close() followed by + // nitf_IOInterface_destruct(). But at that point CustomIO no longer + // exists, so the data variable passed into these functions is invalid. + // By NULL'ing it out here, and by supporting a passthrough when data + // comes in NULL in adapterClose() below, we make the close call safe. + // Additionally, the nitf_IOInterface_destruct call would try to free our + // 'data' member via NRT_FREE() if we didn't do this - that would also + // be exceptionally bad. + mHandle->get()->data = NULL; +} + +nitf_IOInterface* CustomIO::createInterface(CustomIO* me) +{ + static nrt_IIOInterface iIOHandle = { + &CustomIO::adapterRead, + &CustomIO::adapterWrite, + &CustomIO::adapterCanSeek, + &CustomIO::adapterSeek, + &CustomIO::adapterTell, + &CustomIO::adapterGetSize, + &CustomIO::adapterGetMode, + &CustomIO::adapterClose, + &CustomIO::adapterDestruct + }; + + nitf_IOInterface* const impl = + (nitf_IOInterface *)NITF_MALLOC(sizeof(nitf_IOInterface)); + if (impl == NULL) + { + return NULL; + } + memset(impl, 0, sizeof(nitf_IOInterface)); + + impl->data = me; + impl->iface = &iIOHandle; + return impl; +} + +NRT_BOOL CustomIO::adapterRead(NRT_DATA* data, + char* buf, + size_t size, + nrt_Error* error) +{ + try + { + reinterpret_cast(data)->readImpl(buf, size); + return NRT_SUCCESS; + } + catch (const except::Exception& ex) + { + nrt_Error_init(error, ex.getMessage().c_str(), NRT_CTXT, + NRT_ERR_READING_FROM_FILE); + return NRT_FAILURE; + } + catch (const std::exception& ex) + { + nrt_Error_init(error, ex.what(), NRT_CTXT, + NRT_ERR_READING_FROM_FILE); + return NRT_FAILURE; + } + catch (...) + { + nrt_Error_init(error, "Unknown error", NRT_CTXT, + NRT_ERR_READING_FROM_FILE); + return NRT_FAILURE; + } +} + +NRT_BOOL CustomIO::adapterWrite(NRT_DATA* data, + const char* buf, + size_t size, + nrt_Error* error) +{ + try + { + reinterpret_cast(data)->writeImpl(buf, size); + return NRT_SUCCESS; + } + catch (const except::Exception& ex) + { + nrt_Error_init(error, ex.getMessage().c_str(), NRT_CTXT, + NRT_ERR_WRITING_TO_FILE); + return NRT_FAILURE; + } + catch (const std::exception& ex) + { + nrt_Error_init(error, ex.what(), NRT_CTXT, + NRT_ERR_WRITING_TO_FILE); + return NRT_FAILURE; + } + catch (...) + { + nrt_Error_init(error, "Unknown error", NRT_CTXT, + NRT_ERR_WRITING_TO_FILE); + return NRT_FAILURE; + } +} + +NRT_BOOL CustomIO::adapterCanSeek(NRT_DATA* data, + nrt_Error* error) +{ + try + { + reinterpret_cast(data)->canSeekImpl(); + return NRT_SUCCESS; + } + catch (const except::Exception& ex) + { + nrt_Error_init(error, ex.getMessage().c_str(), NRT_CTXT, + NRT_ERR_SEEKING_IN_FILE); + return NRT_FAILURE; + } + catch (const std::exception& ex) + { + nrt_Error_init(error, ex.what(), NRT_CTXT, + NRT_ERR_SEEKING_IN_FILE); + return NRT_FAILURE; + } + catch (...) + { + nrt_Error_init(error, "Unknown error", NRT_CTXT, + NRT_ERR_SEEKING_IN_FILE); + return NRT_FAILURE; + } +} + +nrt_Off CustomIO::adapterSeek(NRT_DATA* data, + nrt_Off offset, + int whence, + nrt_Error* error) +{ + try + { + return reinterpret_cast(data)->seekImpl(offset, whence); + } + catch (const except::Exception& ex) + { + nrt_Error_init(error, ex.getMessage().c_str(), NRT_CTXT, + NRT_ERR_SEEKING_IN_FILE); + return -1; + } + catch (const std::exception& ex) + { + nrt_Error_init(error, ex.what(), NRT_CTXT, + NRT_ERR_SEEKING_IN_FILE); + return -1; + } + catch (...) + { + nrt_Error_init(error, "Unknown error", NRT_CTXT, + NRT_ERR_SEEKING_IN_FILE); + return -1; + } +} + +nrt_Off CustomIO::adapterTell(NRT_DATA* data, + nrt_Error* error) +{ + try + { + return reinterpret_cast(data)->tellImpl(); + } + catch (const except::Exception& ex) + { + nrt_Error_init(error, ex.getMessage().c_str(), NRT_CTXT, + NRT_ERR_SEEKING_IN_FILE); + return -1; + } + catch (const std::exception& ex) + { + nrt_Error_init(error, ex.what(), NRT_CTXT, + NRT_ERR_SEEKING_IN_FILE); + return -1; + } + catch (...) + { + nrt_Error_init(error, "Unknown error", NRT_CTXT, + NRT_ERR_SEEKING_IN_FILE); + return -1; + } +} + +nrt_Off CustomIO::adapterGetSize(NRT_DATA* data, + nrt_Error* error) +{ + try + { + return reinterpret_cast(data)->getSizeImpl(); + } + catch (const except::Exception& ex) + { + nrt_Error_init(error, ex.getMessage().c_str(), NRT_CTXT, + NRT_ERR_UNK); + return -1; + } + catch (const std::exception& ex) + { + nrt_Error_init(error, ex.what(), NRT_CTXT, + NRT_ERR_UNK); + return -1; + } + catch (...) + { + nrt_Error_init(error, "Unknown error", NRT_CTXT, + NRT_ERR_UNK); + return -1; + } +} + +int CustomIO::adapterGetMode(NRT_DATA* data, + nrt_Error* error) +{ + try + { + return reinterpret_cast(data)->getMode(); + } + catch (const except::Exception& ex) + { + nrt_Error_init(error, ex.getMessage().c_str(), NRT_CTXT, + NRT_ERR_UNK); + return -1; + } + catch (const std::exception& ex) + { + nrt_Error_init(error, ex.what(), NRT_CTXT, + NRT_ERR_UNK); + return -1; + } + catch (...) + { + nrt_Error_init(error, "Unknown error", NRT_CTXT, + NRT_ERR_UNK); + return -1; + } +} + +NRT_BOOL CustomIO::adapterClose(NRT_DATA* data, + nrt_Error* error) +{ + if (data) + { + try + { + reinterpret_cast(data)->closeImpl(); + return NRT_SUCCESS; + } + catch (const except::Exception& ex) + { + nrt_Error_init(error, ex.getMessage().c_str(), NRT_CTXT, + NRT_ERR_UNK); + return NRT_FAILURE; + } + catch (const std::exception& ex) + { + nrt_Error_init(error, ex.what(), NRT_CTXT, + NRT_ERR_UNK); + return NRT_FAILURE; + } + catch (...) + { + nrt_Error_init(error, "Unknown error", NRT_CTXT, + NRT_ERR_UNK); + return NRT_FAILURE; + } + } + else + { + // See destructor for why this is needed + nrt_Error_init(error, "Handle is NULL", NRT_CTXT, + NRT_ERR_INVALID_OBJECT); + return NRT_FAILURE; + } +} + +void CustomIO::adapterDestruct(NRT_DATA* data) +{ +} +} diff --git a/modules/c++/nitf/source/DESegment.cpp b/modules/c++/nitf/source/DESegment.cpp new file mode 100644 index 000000000..faee45e93 --- /dev/null +++ b/modules/c++/nitf/source/DESegment.cpp @@ -0,0 +1,108 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/DESegment.hpp" + +using namespace nitf; + +DESegment::DESegment(const DESegment & x) +{ + setNative(x.getNative()); +} + +DESegment & DESegment::operator=(const DESegment & x) +{ + if (&x != this) + setNative(x.getNative()); + return *this; +} + +DESegment::DESegment(nitf_DESegment * x) +{ + setNative(x); + getNativeOrThrow(); +} + +DESegment::DESegment() throw(nitf::NITFException) +{ + setNative(nitf_DESegment_construct(&error)); + getNativeOrThrow(); + setManaged(false); +} + +DESegment::DESegment(NITF_DATA * x) +{ + setNative((nitf_DESegment*)x); + getNativeOrThrow(); +} + +DESegment & DESegment::operator=(NITF_DATA * x) +{ + setNative((nitf_DESegment*)x); + getNativeOrThrow(); + return *this; +} + +nitf::DESegment DESegment::clone() throw(nitf::NITFException) +{ + nitf::DESegment dolly(nitf_DESegment_clone(getNativeOrThrow(), &error)); + dolly.setManaged(false); + return dolly; +} + +DESegment::~DESegment(){} + +nitf::DESubheader DESegment::getSubheader() +{ + return nitf::DESubheader(getNativeOrThrow()->subheader); +} + +void DESegment::setSubheader(nitf::DESubheader & value) +{ + //release the one currently "owned" + nitf::DESubheader sub = nitf::DESubheader(getNativeOrThrow()->subheader); + sub.setManaged(false); + + //have the library manage the "new" one + getNativeOrThrow()->subheader = value.getNative(); + value.setManaged(true); +} + +nitf::Uint64 DESegment::getOffset() const +{ + return getNativeOrThrow()->offset; +} + +void DESegment::setOffset(nitf::Uint64 value) +{ + getNativeOrThrow()->offset = value; +} + +nitf::Uint64 DESegment::getEnd() const +{ + return getNativeOrThrow()->end; +} + +void DESegment::setEnd(nitf::Uint64 value) +{ + getNativeOrThrow()->end = value; +} diff --git a/modules/c++/nitf/source/DESubheader.cpp b/modules/c++/nitf/source/DESubheader.cpp new file mode 100644 index 000000000..6eaa25221 --- /dev/null +++ b/modules/c++/nitf/source/DESubheader.cpp @@ -0,0 +1,160 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/DESubheader.hpp" + +using namespace nitf; + +DESubheader::DESubheader(const DESubheader & x) +{ + setNative(x.getNative()); +} + +DESubheader & DESubheader::operator=(const DESubheader & x) +{ + if (&x != this) + setNative(x.getNative()); + return *this; +} + +DESubheader::DESubheader(nitf_DESubheader * x) +{ + setNative(x); + getNativeOrThrow(); +} + +DESubheader::DESubheader() throw(nitf::NITFException) +{ + setNative(nitf_DESubheader_construct(&error)); + getNativeOrThrow(); + setManaged(false); +} + +nitf::DESubheader DESubheader::clone() throw(nitf::NITFException) +{ + nitf::DESubheader dolly(nitf_DESubheader_clone(getNativeOrThrow(), &error)); + dolly.setManaged(false); + return dolly; +} + +DESubheader::~DESubheader(){} + +nitf::Field DESubheader::getFilePartType() +{ + return nitf::Field(getNativeOrThrow()->filePartType); +} + +nitf::Field DESubheader::getTypeID() +{ + return nitf::Field(getNativeOrThrow()->typeID); +} + +nitf::Field DESubheader::getVersion() +{ + return nitf::Field(getNativeOrThrow()->version); +} + +nitf::Field DESubheader::getSecurityClass() +{ + return nitf::Field(getNativeOrThrow()->securityClass); +} + +nitf::FileSecurity DESubheader::getSecurityGroup() +{ + return nitf::FileSecurity(getNativeOrThrow()->securityGroup); +} + +void DESubheader::setSecurityGroup(nitf::FileSecurity value) +{ + //release the owned security group + nitf::FileSecurity fs = nitf::FileSecurity(getNativeOrThrow()->securityGroup); + fs.setManaged(false); + + //have the library manage the new securitygroup + getNativeOrThrow()->securityGroup = value.getNative(); + value.setManaged(true); +} + +nitf::Field DESubheader::getOverflowedHeaderType() +{ + return nitf::Field(getNativeOrThrow()->overflowedHeaderType); +} + +nitf::Field DESubheader::getDataItemOverflowed() +{ + return nitf::Field(getNativeOrThrow()->dataItemOverflowed); +} + +nitf::Field DESubheader::getSubheaderFieldsLength() +{ + return nitf::Field(getNativeOrThrow()->subheaderFieldsLength); +} + +nitf::TRE DESubheader::getSubheaderFields() +{ + return nitf::TRE(getNativeOrThrow()->subheaderFields); +} + +void DESubheader::setSubheaderFields(nitf::TRE fields) +{ + if (getNativeOrThrow()->subheaderFields) + { + //release the one currently "owned", if different + nitf::TRE tre = nitf::TRE(getNativeOrThrow()->subheaderFields); + if (tre != fields) + tre.setManaged(false); + } + + //have the library manage the "new" one + getNativeOrThrow()->subheaderFields = fields.getNative(); + fields.setManaged(true); +} + +nitf::Uint32 DESubheader::getDataLength() const +{ + return getNativeOrThrow()->dataLength; +} + +void DESubheader::setDataLength(nitf::Uint32 value) +{ + getNativeOrThrow()->dataLength = value; +} + +nitf::Extensions DESubheader::getUserDefinedSection() +{ + return nitf::Extensions(getNativeOrThrow()->userDefinedSection); +} + +void DESubheader::setUserDefinedSection(nitf::Extensions value) +{ + if (getNativeOrThrow()->userDefinedSection) + { + //release the one currently "owned", if different + nitf::Extensions exts = nitf::Extensions(getNativeOrThrow()->userDefinedSection); + if (exts != value) + exts.setManaged(false); + } + + //have the library manage the "new" one + getNativeOrThrow()->userDefinedSection = value.getNative(); + value.setManaged(true); +} diff --git a/modules/c++/nitf/source/DataSource.cpp b/modules/c++/nitf/source/DataSource.cpp new file mode 100644 index 000000000..cd733347d --- /dev/null +++ b/modules/c++/nitf/source/DataSource.cpp @@ -0,0 +1,52 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/DataSource.hpp" + +void nitf::DataSource::read(char * buf, nitf::Off size) + throw (nitf::NITFException) +{ + nitf_DataSource *ds = getNativeOrThrow(); + if (ds && ds->iface) + { + if (!ds->iface->read(ds->data, buf, size, &error)) + throw nitf::NITFException(&error); + } + else + throw except::NullPointerReference(Ctxt("DataSource")); +} + +nitf::Off nitf::DataSource::getSize() +{ + nitf_DataSource *ds = getNativeOrThrow(); + nitf::Off size = ds->iface->getSize(ds->data, &error); + if (size < 0) + throw nitf::NITFException(&error); + return size; +} + +void nitf::DataSource::setSize(nitf::Off size) +{ + nitf_DataSource *ds = getNativeOrThrow(); + if (!ds->iface->setSize(ds->data, size, &error)) + throw nitf::NITFException(&error); +} diff --git a/modules/c++/nitf/source/DateTime.cpp b/modules/c++/nitf/source/DateTime.cpp new file mode 100644 index 000000000..29986afbc --- /dev/null +++ b/modules/c++/nitf/source/DateTime.cpp @@ -0,0 +1,241 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "sys/Conf.h" +#include "nitf/DateTime.hpp" + +nitf::DateTime::DateTime() throw (nitf::NITFException) +{ + nitf_Error error; + mDateTime = nitf_DateTime_now(&error); + if (!mDateTime) + { + throw nitf::NITFException(&error); + } +} + +nitf::DateTime::DateTime(nitf_DateTime* dateTime) throw(nitf::NITFException) : + mDateTime(dateTime) +{ + if (!dateTime) + { + throw nitf::NITFException(Ctxt("Invalid handle")); + } +} + +nitf::DateTime::DateTime(double timeInMillis) throw (nitf::NITFException) +{ + nitf_Error error; + mDateTime = nitf_DateTime_fromMillis(timeInMillis, &error); + if (!mDateTime) + { + throw nitf::NITFException(&error); + } +} + +nitf::DateTime::DateTime(const std::string& dateString, + const std::string& dateFormat) throw (nitf::NITFException) +{ + nitf_Error error; + mDateTime = + nitf_DateTime_fromString(dateString.c_str(), dateFormat.c_str(), + &error); + if (!mDateTime) + { + throw nitf::NITFException(&error); + } +} + +nitf::DateTime::~DateTime() +{ + nitf_DateTime_destruct(&mDateTime); +} + +nitf::DateTime::DateTime(const nitf::DateTime& rhs) +{ + nitf_Error error; + mDateTime = nitf_DateTime_fromMillis(rhs.getTimeInMillis(), &error); + if (!mDateTime) + { + throw nitf::NITFException(&error); + } +} + +nitf::DateTime & nitf::DateTime::operator=(const nitf::DateTime& rhs) +{ + if (&rhs != this) + { + nitf_Error error; + nitf_DateTime* const dateTime = + nitf_DateTime_fromMillis(rhs.getTimeInMillis(), &error); + if (!dateTime) + { + throw nitf::NITFException(&error); + } + + nitf_DateTime_destruct(&mDateTime); + mDateTime = dateTime; + } + + return *this; +} + +void nitf::DateTime::format(const std::string& format, char* outBuf, + size_t maxSize) const throw (nitf::NITFException) +{ + nitf_Error error; + if (!nitf_DateTime_format(mDateTime, + format.c_str(), + outBuf, + maxSize, + &error)) + { + throw nitf::NITFException(&error); + } +} + +void nitf::DateTime::format(const std::string& format, + std::string &str) const throw(nitf::NITFException) +{ + str.clear(); + + char raw[256]; + raw[255] = '\0'; + this->format(format, raw, 255); + str.assign(raw); +} + +std::string nitf::DateTime::format(const std::string& format) const + throw(nitf::NITFException) +{ + std::string str; + this->format(format, str); + return str; +} + +int nitf::DateTime::getYear() const +{ + return mDateTime->year; +} +int nitf::DateTime::getMonth() const +{ + return mDateTime->month; +} +int nitf::DateTime::getDayOfMonth() const +{ + return mDateTime->dayOfMonth; +} +int nitf::DateTime::getDayOfWeek() const +{ + return mDateTime->dayOfWeek; +} +int nitf::DateTime::getDayOfYear() const +{ + return mDateTime->dayOfYear; +} +int nitf::DateTime::getHour() const +{ + return mDateTime->hour; +} +int nitf::DateTime::getMinute() const +{ + return mDateTime->minute; +} +double nitf::DateTime::getSecond() const +{ + return mDateTime->second; +} +double nitf::DateTime::getTimeInMillis() const +{ + return mDateTime->timeInMillis; +} + +void nitf::DateTime::setYear(int year) +{ + nitf_Error error; + if (nitf_DateTime_setYear(mDateTime, + year, + &error) != NITF_SUCCESS) + { + throw nitf::NITFException(&error); + } +} +void nitf::DateTime::setMonth(int month) +{ + nitf_Error error; + if (nitf_DateTime_setMonth(mDateTime, + month, + &error) != NITF_SUCCESS) + { + throw nitf::NITFException(&error); + } +} +void nitf::DateTime::setDayOfMonth(int dayOfMonth) +{ + nitf_Error error; + if (nitf_DateTime_setDayOfMonth(mDateTime, + dayOfMonth, + &error) != NITF_SUCCESS) + { + throw nitf::NITFException(&error); + } +} +void nitf::DateTime::setHour(int hour) +{ + nitf_Error error; + if (nitf_DateTime_setHour(mDateTime, + hour, + &error) != NITF_SUCCESS) + { + throw nitf::NITFException(&error); + } +} +void nitf::DateTime::setMinute(int minute) +{ + nitf_Error error; + if (nitf_DateTime_setMinute(mDateTime, + minute, + &error) != NITF_SUCCESS) + { + throw nitf::NITFException(&error); + } +} +void nitf::DateTime::setSecond(double second) +{ + nitf_Error error; + if (nitf_DateTime_setSecond(mDateTime, + second, + &error) != NITF_SUCCESS) + { + throw nitf::NITFException(&error); + } +} +void nitf::DateTime::setTimeInMillis(double timeInMillis) +{ + nitf_Error error; + if (nitf_DateTime_setTimeInMillis(mDateTime, + timeInMillis, + &error) != NITF_SUCCESS) + { + throw nitf::NITFException(&error); + } +} diff --git a/modules/c++/nitf/source/DecompressionInterface.cpp b/modules/c++/nitf/source/DecompressionInterface.cpp new file mode 100644 index 000000000..d952d244a --- /dev/null +++ b/modules/c++/nitf/source/DecompressionInterface.cpp @@ -0,0 +1,141 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include +#include + +using namespace nitf; + +NITF_BOOL DecompressionInterface::adapterStart( + nitf_DecompressionControl* object, + nitf_IOInterface* io, + nitf_Uint64 offset, + nitf_Uint64 fileLength, + nitf_BlockingInfo* blockingDefinition, + nitf_Uint64* blockMask, + nitf_Error* error) +{ + try + { + nitf::IOInterface ioInter(io); + ioInter.setManaged(true); + nitf::BlockingInfo blockInfo(blockingDefinition); + blockInfo.setManaged(true); + reinterpret_cast(object)->start(ioInter, + offset, + fileLength, + blockInfo, + blockMask); + return NRT_SUCCESS; + } + catch (const except::Exception& ex) + { + nrt_Error_init(error, ex.getMessage().c_str(), NRT_CTXT, + NRT_ERR_DECOMPRESSION); + return NRT_FAILURE; + } + catch (const std::exception& ex) + { + nrt_Error_init(error, ex.what(), NRT_CTXT, + NRT_ERR_DECOMPRESSION); + return NRT_FAILURE; + } + catch (...) + { + nrt_Error_init(error, "Unknown error", NRT_CTXT, + NRT_ERR_DECOMPRESSION); + return NRT_FAILURE; + } +} + +nitf_Uint8* DecompressionInterface::adapterReadBlock( + nitf_DecompressionControl* object, + nitf_Uint32 blockNumber, + nitf_Uint64* blockSize, + nitf_Error* error) +{ + try + { + return reinterpret_cast(object)->readBlock(blockNumber, + blockSize); + } + catch (const except::Exception& ex) + { + nrt_Error_init(error, ex.getMessage().c_str(), NRT_CTXT, + NRT_ERR_DECOMPRESSION); + return NULL; + } + catch (const std::exception& ex) + { + nrt_Error_init(error, ex.what(), NRT_CTXT, + NRT_ERR_DECOMPRESSION); + return NULL; + } + catch (...) + { + nrt_Error_init(error, "Unknown error", NRT_CTXT, + NRT_ERR_DECOMPRESSION); + return NULL; + } +} + +NITF_BOOL DecompressionInterface::adapterFreeBlock( + nitf_DecompressionControl* object, + nitf_Uint8* block, + nitf_Error* error) +{ + try + { + reinterpret_cast(object)->freeBlock(block); + return NRT_SUCCESS; + } + catch (const except::Exception& ex) + { + nrt_Error_init(error, ex.getMessage().c_str(), NRT_CTXT, + NRT_ERR_DECOMPRESSION); + return NRT_FAILURE; + } + catch (const std::exception& ex) + { + nrt_Error_init(error, ex.what(), NRT_CTXT, + NRT_ERR_DECOMPRESSION); + return NRT_FAILURE; + } + catch (...) + { + nrt_Error_init(error, "Unknown error", NRT_CTXT, + NRT_ERR_DECOMPRESSION); + return NRT_FAILURE; + } +} + +void DecompressionInterface::adapterDestroy( + nitf_DecompressionControl** object) +{ + if (object != NULL && *object != NULL) + { + delete reinterpret_cast(*object); + *object = NULL; + } +} + + diff --git a/modules/c++/nitf/source/DownSampler.cpp b/modules/c++/nitf/source/DownSampler.cpp new file mode 100644 index 000000000..54ad1422c --- /dev/null +++ b/modules/c++/nitf/source/DownSampler.cpp @@ -0,0 +1,100 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/DownSampler.hpp" + +nitf::Uint32 nitf::DownSampler::getRowSkip() +{ + return getNativeOrThrow()->rowSkip; +} + +nitf::Uint32 nitf::DownSampler::getColSkip() +{ + return getNativeOrThrow()->colSkip; +} + +void nitf::DownSampler::apply(NITF_DATA ** inputWindow, + NITF_DATA ** outputWindow, nitf::Uint32 numBands, + nitf::Uint32 numWindowRows, nitf::Uint32 numWindowCols, + nitf::Uint32 numInputCols, nitf::Uint32 numSubWindowCols, + nitf::Uint32 pixelType, nitf::Uint32 pixelSize, + nitf::Uint32 rowsInLastWindow, nitf::Uint32 colsInLastWindow) + throw (nitf::NITFException) +{ + nitf_DownSampler *ds = getNativeOrThrow(); + if (ds && ds->iface) + { + if (!ds->iface->apply(ds, inputWindow, outputWindow, numBands, + numWindowRows, numWindowCols, numInputCols, + numSubWindowCols, pixelType, pixelSize, + rowsInLastWindow, colsInLastWindow, &error)) + throw nitf::NITFException(&error); + } + else + { + throw except::NullPointerReference(Ctxt("DownSampler")); + } +} + +nitf::PixelSkip::PixelSkip(nitf::Uint32 rowSkip, nitf::Uint32 colSkip) + throw (nitf::NITFException) +{ + setNative(nitf_PixelSkip_construct(rowSkip, colSkip, &error)); + setManaged(false); +} + +nitf::PixelSkip::~PixelSkip() +{ +} + +nitf::MaxDownSample::MaxDownSample(nitf::Uint32 rowSkip, nitf::Uint32 colSkip) + throw (nitf::NITFException) +{ + setNative(nitf_MaxDownSample_construct(rowSkip, colSkip, &error)); + setManaged(false); +} + +nitf::MaxDownSample::~MaxDownSample() +{ +} + +nitf::SumSq2DownSample::SumSq2DownSample(nitf::Uint32 rowSkip, + nitf::Uint32 colSkip) throw (nitf::NITFException) +{ + setNative(nitf_SumSq2DownSample_construct(rowSkip, colSkip, &error)); + setManaged(false); +} + +nitf::SumSq2DownSample::~SumSq2DownSample() +{ +} + +nitf::Select2DownSample::Select2DownSample(nitf::Uint32 rowSkip, + nitf::Uint32 colSkip) throw (nitf::NITFException) +{ + setNative(nitf_Select2DownSample_construct(rowSkip, colSkip, &error)); + setManaged(false); +} + +nitf::Select2DownSample::~Select2DownSample() +{ +} diff --git a/modules/c++/nitf/source/FileHeader.cpp b/modules/c++/nitf/source/FileHeader.cpp new file mode 100644 index 000000000..20a565195 --- /dev/null +++ b/modules/c++/nitf/source/FileHeader.cpp @@ -0,0 +1,309 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/FileHeader.hpp" + +using namespace nitf; + +FileHeader::FileHeader(const FileHeader & x) +{ + setNative(x.getNative()); +} + +FileHeader & FileHeader::operator=(const FileHeader & x) +{ + if (&x != this) + setNative(x.getNative()); + return *this; +} + +FileHeader::FileHeader(nitf_FileHeader * x) +{ + setNative(x); + getNativeOrThrow(); +} + +FileHeader::FileHeader() throw(nitf::NITFException) +{ + setNative(nitf_FileHeader_construct(&error)); + getNativeOrThrow(); + setManaged(false); +} + + +nitf::FileHeader FileHeader::clone() throw(nitf::NITFException) +{ + nitf::FileHeader dolly(nitf_FileHeader_clone(getNativeOrThrow(), &error)); + dolly.setManaged(false); + return dolly; +} + +FileHeader::~FileHeader(){} + +nitf::Field FileHeader::getFileHeader() +{ + return nitf::Field(getNativeOrThrow()->fileHeader); +} + +nitf::Field FileHeader::getFileVersion() +{ + return nitf::Field(getNativeOrThrow()->fileVersion); +} + +nitf::Field FileHeader::getComplianceLevel() +{ + return nitf::Field(getNativeOrThrow()->complianceLevel); +} + +nitf::Field FileHeader::getSystemType() +{ + return nitf::Field(getNativeOrThrow()->systemType); +} + +nitf::Field FileHeader::getOriginStationID() +{ + return nitf::Field(getNativeOrThrow()->originStationID); +} + +nitf::Field FileHeader::getFileDateTime() +{ + return nitf::Field(getNativeOrThrow()->fileDateTime); +} + +nitf::Field FileHeader::getFileTitle() +{ + return nitf::Field(getNativeOrThrow()->fileTitle); +} + +nitf::Field FileHeader::getClassification() +{ + return nitf::Field(getNativeOrThrow()->classification); +} + +nitf::FileSecurity FileHeader::getSecurityGroup() +{ + return nitf::FileSecurity(getNativeOrThrow()->securityGroup); +} + +void FileHeader::setSecurityGroup(nitf::FileSecurity value) +{ + //release the owned security group + nitf::FileSecurity fs = nitf::FileSecurity(getNativeOrThrow()->securityGroup); + fs.setManaged(false); + + //have the library manage the new securitygroup + getNativeOrThrow()->securityGroup = value.getNative(); + value.setManaged(true); +} + +nitf::Field FileHeader::getMessageCopyNum() +{ + return nitf::Field(getNativeOrThrow()->messageCopyNum); +} + +nitf::Field FileHeader::getMessageNumCopies() +{ + return nitf::Field(getNativeOrThrow()->messageNumCopies); +} + +nitf::Field FileHeader::getEncrypted() +{ + return nitf::Field(getNativeOrThrow()->encrypted); +} + +nitf::Field FileHeader::getBackgroundColor() +{ + return nitf::Field(getNativeOrThrow()->backgroundColor); +} + +nitf::Field FileHeader::getOriginatorName() +{ + return nitf::Field(getNativeOrThrow()->originatorName); +} + +nitf::Field FileHeader::getOriginatorPhone() +{ + return nitf::Field(getNativeOrThrow()->originatorPhone); +} + +nitf::Field FileHeader::getFileLength() +{ + return nitf::Field(getNativeOrThrow()->fileLength); +} + +nitf::Field FileHeader::getHeaderLength() +{ + return nitf::Field(getNativeOrThrow()->headerLength); +} + +nitf::Field FileHeader::getNumImages() +{ + return nitf::Field(getNativeOrThrow()->numImages); +} + +nitf::Field FileHeader::getNumGraphics() +{ + return nitf::Field(getNativeOrThrow()->numGraphics); +} + +nitf::Field FileHeader::getNumLabels() +{ + return nitf::Field(getNativeOrThrow()->numLabels); +} + +nitf::Field FileHeader::getNumTexts() +{ + return nitf::Field(getNativeOrThrow()->numTexts); +} + +nitf::Field FileHeader::getNumDataExtensions() +{ + return nitf::Field(getNativeOrThrow()->numDataExtensions); +} + +nitf::Field FileHeader::getNumReservedExtensions() +{ + return nitf::Field(getNativeOrThrow()->numReservedExtensions); +} + +nitf::ComponentInfo FileHeader::getImageInfo(int i) + throw(except::IndexOutOfRangeException) +{ + int num = getNumImages(); + if (i < 0 || i >= num) + throw except::IndexOutOfRangeException(Ctxt(FmtX( + "Index out of range: (%d <= %d <= %d)", 0, i, num))); + return nitf::ComponentInfo(getNativeOrThrow()->imageInfo[i]); +} + +nitf::ComponentInfo FileHeader::getGraphicInfo(int i) + throw(except::IndexOutOfRangeException) +{ + int num = getNumGraphics(); + if (i < 0 || i >= num) + throw except::IndexOutOfRangeException(Ctxt(FmtX( + "Index out of range: (%d <= %d <= %d)", 0, i, num))); + return nitf::ComponentInfo(getNativeOrThrow()->graphicInfo[i]); +} + +nitf::ComponentInfo FileHeader::getLabelInfo(int i) + throw(except::IndexOutOfRangeException) +{ + int num = getNumLabels(); + if (i < 0 || i >= num) + throw except::IndexOutOfRangeException(Ctxt(FmtX( + "Index out of range: (%d <= %d <= %d)", 0, i, num))); + return nitf::ComponentInfo(getNativeOrThrow()->labelInfo[i]); +} + +nitf::ComponentInfo FileHeader::getTextInfo(int i) + throw(except::IndexOutOfRangeException) +{ + int num = getNumTexts(); + if (i < 0 || i >= num) + throw except::IndexOutOfRangeException(Ctxt(FmtX( + "Index out of range: (%d <= %d <= %d)", 0, i, num))); + return nitf::ComponentInfo(getNativeOrThrow()->textInfo[i]); +} + +nitf::ComponentInfo FileHeader::getDataExtensionInfo(int i) + throw(except::IndexOutOfRangeException) +{ + int num = getNumDataExtensions(); + if (i < 0 || i >= num) + throw except::IndexOutOfRangeException(Ctxt(FmtX( + "Index out of range: (%d <= %d <= %d)", 0, i, num))); + return nitf::ComponentInfo(getNativeOrThrow()->dataExtensionInfo[i]); +} + +nitf::ComponentInfo FileHeader::getReservedExtensionInfo(int i) + throw(except::IndexOutOfRangeException) +{ + int num = getNumReservedExtensions(); + if (i < 0 || i >= num) + throw except::IndexOutOfRangeException(Ctxt(FmtX( + "Index out of range: (%d <= %d <= %d)", 0, i, num))); + return nitf::ComponentInfo(getNativeOrThrow()->reservedExtensionInfo[i]); +} + +nitf::Field FileHeader::getUserDefinedHeaderLength() +{ + return nitf::Field(getNativeOrThrow()->userDefinedHeaderLength); +} + +nitf::Field FileHeader::getUserDefinedOverflow() +{ + return nitf::Field(getNativeOrThrow()->userDefinedOverflow); +} + +nitf::Field FileHeader::getExtendedHeaderLength() +{ + return nitf::Field(getNativeOrThrow()->extendedHeaderLength); +} + +nitf::Field FileHeader::getExtendedHeaderOverflow() +{ + return nitf::Field(getNativeOrThrow()->extendedHeaderOverflow); +} + +nitf::Extensions FileHeader::getUserDefinedSection() +{ + return nitf::Extensions(getNativeOrThrow()->userDefinedSection); +} + +void FileHeader::setUserDefinedSection(nitf::Extensions value) +{ + if (getNativeOrThrow()->userDefinedSection) + { + //release the one currently "owned", if different + nitf::Extensions exts = nitf::Extensions(getNativeOrThrow()->userDefinedSection); + if (exts != value) + exts.setManaged(false); + } + + //have the library manage the "new" one + getNativeOrThrow()->userDefinedSection = value.getNative(); + nitf::Extensions(value).setManaged(true); + value.setManaged(true); +} + + +nitf::Extensions FileHeader::getExtendedSection() +{ + return nitf::Extensions(getNativeOrThrow()->extendedSection); +} + +void FileHeader::setExtendedSection(nitf::Extensions value) +{ + if (getNativeOrThrow()->extendedSection) + { + //release the one currently "owned", if different + nitf::Extensions exts = nitf::Extensions(getNativeOrThrow()->extendedSection); + if (exts != value) + exts.setManaged(false); + } + + //have the library manage the "new" one + getNativeOrThrow()->extendedSection = value.getNative(); + value.setManaged(true); +} + diff --git a/modules/c++/nitf/source/FileSecurity.cpp b/modules/c++/nitf/source/FileSecurity.cpp new file mode 100644 index 000000000..cd0a71f72 --- /dev/null +++ b/modules/c++/nitf/source/FileSecurity.cpp @@ -0,0 +1,135 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/FileSecurity.hpp" + +using namespace nitf; + +FileSecurity::FileSecurity(const FileSecurity & x) +{ + setNative(x.getNative()); +} + +FileSecurity & FileSecurity::operator=(const FileSecurity & x) +{ + if (&x != this) + setNative(x.getNative()); + return *this; +} + +FileSecurity::FileSecurity(nitf_FileSecurity * x) +{ + setNative(x); + getNativeOrThrow(); +} + +FileSecurity::FileSecurity() throw(nitf::NITFException) +{ + setNative(nitf_FileSecurity_construct(&error)); + getNativeOrThrow(); + setManaged(false); +} + +nitf::FileSecurity FileSecurity::clone() throw(nitf::NITFException) +{ + nitf::FileSecurity dolly(nitf_FileSecurity_clone(getNativeOrThrow(), &error)); + dolly.setManaged(false); + return dolly; +} + +FileSecurity::~FileSecurity(){} + + +nitf::Field FileSecurity::getClassificationSystem() +{ + return nitf::Field(getNativeOrThrow()->classificationSystem); +} + +nitf::Field FileSecurity::getCodewords() +{ + return nitf::Field(getNativeOrThrow()->codewords); +} + +nitf::Field FileSecurity::getControlAndHandling() +{ + return nitf::Field(getNativeOrThrow()->controlAndHandling); +} + +nitf::Field FileSecurity::getReleasingInstructions() +{ + return nitf::Field(getNativeOrThrow()->releasingInstructions); +} + +nitf::Field FileSecurity::getDeclassificationType() +{ + return nitf::Field(getNativeOrThrow()->declassificationType); +} + +nitf::Field FileSecurity::getDeclassificationDate() +{ + return nitf::Field(getNativeOrThrow()->declassificationDate); +} + +nitf::Field FileSecurity::getDeclassificationExemption() +{ + return nitf::Field(getNativeOrThrow()->declassificationExemption); +} + +nitf::Field FileSecurity::getDowngrade() +{ + return nitf::Field(getNativeOrThrow()->downgrade); +} + +nitf::Field FileSecurity::getDowngradeDateTime() +{ + return nitf::Field(getNativeOrThrow()->downgradeDateTime); +} + +nitf::Field FileSecurity::getClassificationText() +{ + return nitf::Field(getNativeOrThrow()->classificationText); +} + +nitf::Field FileSecurity::getClassificationAuthorityType() +{ + return nitf::Field(getNativeOrThrow()->classificationAuthorityType); +} + +nitf::Field FileSecurity::getClassificationAuthority() +{ + return nitf::Field(getNativeOrThrow()->classificationAuthority); +} + +nitf::Field FileSecurity::getClassificationReason() +{ + return nitf::Field(getNativeOrThrow()->classificationReason); +} + +nitf::Field FileSecurity::getSecuritySourceDate() +{ + return nitf::Field(getNativeOrThrow()->securitySourceDate); +} + +nitf::Field FileSecurity::getSecurityControlNumber() +{ + return nitf::Field(getNativeOrThrow()->securityControlNumber); +} diff --git a/modules/c++/nitf/source/GraphicSegment.cpp b/modules/c++/nitf/source/GraphicSegment.cpp new file mode 100644 index 000000000..a817517f4 --- /dev/null +++ b/modules/c++/nitf/source/GraphicSegment.cpp @@ -0,0 +1,112 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/GraphicSegment.hpp" + +using namespace nitf; + +GraphicSegment::GraphicSegment(const GraphicSegment & x) +{ + setNative(x.getNative()); +} + +GraphicSegment & GraphicSegment::operator=(const GraphicSegment & x) +{ + if (&x != this) + setNative(x.getNative()); + return *this; +} + + +GraphicSegment::GraphicSegment(nitf_GraphicSegment * x) +{ + setNative(x); + getNativeOrThrow(); +} + + +GraphicSegment::GraphicSegment() throw(nitf::NITFException) +{ + setNative(nitf_GraphicSegment_construct(&error)); + getNativeOrThrow(); + setManaged(false); +} + +GraphicSegment::GraphicSegment(NITF_DATA * x) +{ + setNative((nitf_GraphicSegment*)x); + getNativeOrThrow(); +} + +GraphicSegment & GraphicSegment::operator=(NITF_DATA * x) +{ + setNative((nitf_GraphicSegment*)x); + getNativeOrThrow(); + return *this; +} + + +nitf::GraphicSegment GraphicSegment::clone() throw(nitf::NITFException) +{ + nitf::GraphicSegment dolly(nitf_GraphicSegment_clone(getNativeOrThrow(), &error)); + dolly.setManaged(false); + return dolly; +} + +GraphicSegment::~GraphicSegment(){} + + +nitf::GraphicSubheader GraphicSegment::getSubheader() +{ + return nitf::GraphicSubheader(getNativeOrThrow()->subheader); +} + +void GraphicSegment::setSubheader(nitf::GraphicSubheader & value) +{ + //release the one currently "owned" + nitf::GraphicSubheader sub = nitf::GraphicSubheader(getNativeOrThrow()->subheader); + sub.setManaged(false); + + //have the library manage the "new" one + getNativeOrThrow()->subheader = value.getNative(); + value.setManaged(true); +} + +nitf::Uint64 GraphicSegment::getOffset() const +{ + return getNativeOrThrow()->offset; +} + +void GraphicSegment::setOffset(nitf::Uint64 value) +{ + getNativeOrThrow()->offset = value; +} + +nitf::Uint64 GraphicSegment::getEnd() const +{ + return getNativeOrThrow()->end; +} + +void GraphicSegment::setEnd(nitf::Uint64 value) +{ + getNativeOrThrow()->end = value; +} diff --git a/modules/c++/nitf/source/GraphicSubheader.cpp b/modules/c++/nitf/source/GraphicSubheader.cpp new file mode 100644 index 000000000..24eadcdc2 --- /dev/null +++ b/modules/c++/nitf/source/GraphicSubheader.cpp @@ -0,0 +1,179 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/GraphicSubheader.hpp" + +using namespace nitf; + +GraphicSubheader::GraphicSubheader(const GraphicSubheader & x) +{ + setNative(x.getNative()); +} + + +GraphicSubheader & GraphicSubheader::operator=(const GraphicSubheader & x) +{ + if (&x != this) + setNative(x.getNative()); + return *this; +} + +GraphicSubheader::GraphicSubheader(nitf_GraphicSubheader * x) +{ + setNative(x); + getNativeOrThrow(); +} + +GraphicSubheader::GraphicSubheader() throw(nitf::NITFException) +{ + setNative(nitf_GraphicSubheader_construct(&error)); + getNativeOrThrow(); + setManaged(false); +} + + +nitf::GraphicSubheader GraphicSubheader::clone() throw(nitf::NITFException) +{ + nitf::GraphicSubheader dolly( + nitf_GraphicSubheader_clone(getNativeOrThrow(), &error)); + dolly.setManaged(false); + return dolly; +} + +GraphicSubheader::~GraphicSubheader(){} + +nitf::Field GraphicSubheader::getFilePartType() +{ + return nitf::Field(getNativeOrThrow()->filePartType); +} + +nitf::Field GraphicSubheader::getGraphicID() +{ + return nitf::Field(getNativeOrThrow()->graphicID); +} + +nitf::Field GraphicSubheader::getName() +{ + return nitf::Field(getNativeOrThrow()->name); +} + +nitf::Field GraphicSubheader::getSecurityClass() +{ + return nitf::Field(getNativeOrThrow()->securityClass); +} + +nitf::FileSecurity GraphicSubheader::getSecurityGroup() +{ + return nitf::FileSecurity(getNativeOrThrow()->securityGroup); +} + +void GraphicSubheader::setSecurityGroup(nitf::FileSecurity value) +{ + //release the owned security group + nitf::FileSecurity fs = nitf::FileSecurity(getNativeOrThrow()->securityGroup); + fs.setManaged(false); + + //have the library manage the new securitygroup + getNativeOrThrow()->securityGroup = value.getNative(); + value.setManaged(true); +} + + +nitf::Field GraphicSubheader::getEncrypted() +{ + return nitf::Field(getNativeOrThrow()->encrypted); +} + +nitf::Field GraphicSubheader::getStype() +{ + return nitf::Field(getNativeOrThrow()->stype); +} + +nitf::Field GraphicSubheader::getRes1() +{ + return nitf::Field(getNativeOrThrow()->res1); +} + +nitf::Field GraphicSubheader::getDisplayLevel() +{ + return nitf::Field(getNativeOrThrow()->displayLevel); +} + +nitf::Field GraphicSubheader::getAttachmentLevel() +{ + return nitf::Field(getNativeOrThrow()->attachmentLevel); +} + +nitf::Field GraphicSubheader::getLocation() +{ + return nitf::Field(getNativeOrThrow()->location); +} + +nitf::Field GraphicSubheader::getBound1Loc() +{ + return nitf::Field(getNativeOrThrow()->bound1Loc); +} + +nitf::Field GraphicSubheader::getColor() +{ + return nitf::Field(getNativeOrThrow()->color); +} + +nitf::Field GraphicSubheader::getBound2Loc() +{ + return nitf::Field(getNativeOrThrow()->bound2Loc); +} + +nitf::Field GraphicSubheader::getRes2() +{ + return nitf::Field(getNativeOrThrow()->res2); +} + +nitf::Field GraphicSubheader::getExtendedHeaderLength() +{ + return nitf::Field(getNativeOrThrow()->extendedHeaderLength); +} + +nitf::Field GraphicSubheader::getExtendedHeaderOverflow() +{ + return nitf::Field(getNativeOrThrow()->extendedHeaderOverflow); +} + +nitf::Extensions GraphicSubheader::getExtendedSection() +{ + return nitf::Extensions(getNativeOrThrow()->extendedSection); +} + +void GraphicSubheader::setExtendedSection(nitf::Extensions value) +{ + if (getNativeOrThrow()->extendedSection) + { + //release the one currently "owned", if different + nitf::Extensions exts = nitf::Extensions(getNativeOrThrow()->extendedSection); + if (exts != value) + exts.setManaged(false); + } + + //have the library manage the "new" one + getNativeOrThrow()->extendedSection = value.getNative(); + value.setManaged(true); +} diff --git a/modules/c++/nitf/source/Handle.cpp b/modules/c++/nitf/source/Handle.cpp new file mode 100644 index 000000000..dac47e9ad --- /dev/null +++ b/modules/c++/nitf/source/Handle.cpp @@ -0,0 +1,24 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/Handle.hpp" +sys::Mutex nitf::Handle::mutex; diff --git a/modules/c++/nitf/source/HashTable.cpp b/modules/c++/nitf/source/HashTable.cpp new file mode 100644 index 000000000..5fa7d18a9 --- /dev/null +++ b/modules/c++/nitf/source/HashTable.cpp @@ -0,0 +1,221 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/HashTable.hpp" + +nitf::HashTableIterator & nitf::HashTableIterator::operator=(const nitf::HashTableIterator & x) +{ + if (&x != this) + handle = x.handle; + return *this; +} + +nitf_HashTableIterator & nitf::HashTableIterator::getHandle() { return handle; } + +bool nitf::HashTableIterator::equals(nitf::HashTableIterator& it2) +{ + NITF_BOOL x = nitf_HashTableIterator_equals(&handle, &it2.getHandle()); + if (!x) return false; + return true; +} + +bool nitf::HashTableIterator::operator==(const nitf::HashTableIterator& it2) +{ + return this->equals((nitf::HashTableIterator&)it2); +} + +bool nitf::HashTableIterator::notEqualTo(nitf::HashTableIterator& it2) +{ + NITF_BOOL x = nitf_HashTableIterator_notEqualTo(&handle, &it2.getHandle()); + if (!x) return false; + return true; +} + +bool nitf::HashTableIterator::operator!=(const nitf::HashTableIterator& it2) +{ + return this->notEqualTo((nitf::HashTableIterator&)it2); +} + +void nitf::HashTableIterator::increment() { nitf_HashTableIterator_increment(&handle); } + +void nitf::HashTableIterator::operator++(int x) { increment(); } + +nitf::HashTableIterator & nitf::HashTableIterator::operator+=(int x) +{ + for (int i = 0; i < x; ++i) + increment(); + return *this; +} + +nitf::HashTableIterator nitf::HashTableIterator::operator+(int x) +{ + nitf::HashTableIterator it = HashTableIterator(*this); + it += x; + return it; +} + + + + +nitf::HashTable::HashTable(const HashTable & x) +{ + setNative(x.getNative()); +} + +nitf::HashTable & nitf::HashTable::operator=(const HashTable & x) +{ + if (&x != this) + setNative(x.getNative()); + return *this; +} + + +nitf::HashTable::HashTable(nitf_HashTable * x) +{ + setNative(x); + getNativeOrThrow(); +} + +nitf::HashTable::HashTable(int nbuckets) throw(nitf::NITFException) +{ + setNative(nitf_HashTable_construct(nbuckets, &error)); + getNativeOrThrow(); + setManaged(false); +} + + +nitf::HashTable nitf::HashTable::clone(NITF_DATA_ITEM_CLONE cloner) throw(nitf::NITFException) +{ + nitf::HashTable dolly(nitf_HashTable_clone(getNativeOrThrow(), + cloner, &error)); + dolly.setManaged(false); + return dolly; +} + +void nitf::HashTable::setPolicy(int policy) +{ + nitf_HashTable_setPolicy(getNative(), policy); +} + +NITF_DATA* nitf::HashTable::remove(const std::string& key) +{ + return nitf_HashTable_remove(getNative(), key.c_str()); +} + +void nitf::HashTable::initDefaults() +{ + nitf_HashTable_initDefaults(getNative()); +} + +nitf::HashTable::~HashTable(){} + +bool nitf::HashTable::exists(const std::string& key) +{ + return nitf_HashTable_exists(getNative(), key.c_str()); +} + +void nitf::HashTable::print() +{ + nitf_HashTable_print(getNative()); +} + +void nitf::HashTable::foreach(HashIterator& fun, NITF_DATA* userData) + throw(nitf::NITFException) +{ + int numBuckets = getNumBuckets(); + for (int i = 0; i < numBuckets; i++) + { + nitf::List l = getBucket(i); + for (nitf::ListIterator iter = l.begin(); + iter != l.end(); ++iter) + { + nitf::Pair pair = nitf::Pair((nitf_Pair*)(*iter)); + fun(this, pair, userData); + } + } +} + +void nitf::HashTable::insert(const std::string& key, NITF_DATA* data) throw(nitf::NITFException) +{ + if (key.length() == 0) + throw except::NoSuchKeyException(Ctxt("Empty key value")); + NITF_BOOL x = nitf_HashTable_insert(getNative(), key.c_str(), data, &error); + if (!x) + throw nitf::NITFException(&error); +} + +nitf::Pair nitf::HashTable::find(const std::string& key) throw(except::NoSuchKeyException) +{ + if (key.length() == 0) + throw except::NoSuchKeyException(Ctxt("Empty key value")); + nitf_Pair* x = nitf_HashTable_find(getNative(), key.c_str()); + if (!x) + throw except::NoSuchKeyException(Ctxt(key)); + return nitf::Pair(x); +} + +nitf::Pair nitf::HashTable::operator[] (const std::string& key) throw(except::NoSuchKeyException) +{ + return find(key); +} + +nitf::List nitf::HashTable::getBucket(int i) throw(nitf::NITFException) +{ + //return *mBuckets.at(i); + if (!getNativeOrThrow()->buckets || !getNativeOrThrow()->buckets[i]) + throw nitf::NITFException(Ctxt("No such bucket")); + return nitf::List(getNativeOrThrow()->buckets[i]); + +} + +int nitf::HashTable::getNumBuckets() const +{ + return getNativeOrThrow()->nbuckets; +} + +int nitf::HashTable::getAdopt() const +{ + return getNativeOrThrow()->adopt; +} + +nitf::HashTableIterator nitf::HashTable::begin() +{ + nitf_HashTableIterator x = nitf_HashTable_begin(getNative()); + return nitf::HashTableIterator(x); +} + +nitf::HashTableIterator nitf::HashTable::end() +{ + nitf_HashTableIterator x = nitf_HashTable_end(getNative()); + return nitf::HashTableIterator(x); +} + +void nitf::HashTable::clearBuckets() +{ + std::vector::iterator i; + i = mBuckets.begin(); + for (; i != mBuckets.end(); ++i) + { + if (*i) delete *i; + } + mBuckets.clear(); +} diff --git a/modules/c++/nitf/source/IOHandle.cpp b/modules/c++/nitf/source/IOHandle.cpp new file mode 100644 index 000000000..66509f2dd --- /dev/null +++ b/modules/c++/nitf/source/IOHandle.cpp @@ -0,0 +1,59 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + +namespace nitf +{ +IOHandle::IOHandle(const std::string& fname, + nitf::AccessFlags access, + nitf::CreationFlags creation) throw (nitf::NITFException) : + IOInterface(open(fname.c_str(), access, creation)) +{ + setManaged(false); +} + +IOHandle::IOHandle(const char* fname, + nitf::AccessFlags access, + nitf::CreationFlags creation) throw (nitf::NITFException) : + IOInterface(open(fname, access, creation)) +{ + setManaged(false); +} + +nitf_IOInterface* +IOHandle::open(const char* fname, + nitf::AccessFlags access, + nitf::CreationFlags creation) throw (nitf::NITFException) +{ + nitf_Error error; + nitf_IOInterface* const interface = + nitf_IOHandleAdapter_open(fname, access, creation, &error); + + if (!interface) + { + throw nitf::NITFException(&error); + } + + return interface; +} +} diff --git a/modules/c++/nitf/source/IOInterface.cpp b/modules/c++/nitf/source/IOInterface.cpp new file mode 100644 index 000000000..bc0ddcd8d --- /dev/null +++ b/modules/c++/nitf/source/IOInterface.cpp @@ -0,0 +1,99 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/IOInterface.hpp" + +void nitf::IOInterfaceDestructor::operator()(nitf_IOInterface *io) +{ + if (io) + { + nitf_Error error; + nitf_IOInterface_close(io, &error); + nitf_IOInterface_destruct(&io); + } +} + +void nitf::IOInterface::read(char * buf, size_t size) +{ + nitf_IOInterface *io = getNativeOrThrow(); + NITF_BOOL x = io->iface->read(io->data, buf, size, &error); + if (!x) + throw nitf::NITFException(&error); +} + +void nitf::IOInterface::write(const char * buf, size_t size) +{ + nitf_IOInterface *io = getNativeOrThrow(); + NITF_BOOL x = io->iface->write(io->data, buf, size, &error); + if (!x) + throw nitf::NITFException(&error); +} + +bool nitf::IOInterface::canSeek() const +{ + nitf_IOInterface *io = getNativeOrThrow(); + return io->iface->canSeek(io->data, &error) == NRT_SUCCESS; +} + +nitf::Off nitf::IOInterface::seek(nitf::Off offset, int whence) +{ + nitf_IOInterface *io = getNativeOrThrow(); + if (!NRT_IO_SUCCESS(io->iface->seek(io->data, offset, whence, &error))) + { + throw nitf::NITFException(&error); + } + return io->iface->tell(io->data, &error); +} + +nitf::Off nitf::IOInterface::tell() const +{ + nitf_IOInterface *io = getNativeOrThrow(); + const nitf::Off t = io->iface->tell(io->data, &error); + if (!NRT_IO_SUCCESS(t)) + { + throw nitf::NITFException(&error); + } + return t; +} + +nitf::Off nitf::IOInterface::getSize() const +{ + nitf_IOInterface *io = getNativeOrThrow(); + const nitf::Off size = io->iface->getSize(io->data, &error); + if (!NRT_IO_SUCCESS(size)) + { + throw nitf::NITFException(&error); + } + return size; +} + +int nitf::IOInterface::getMode() const +{ + nitf_IOInterface *io = getNativeOrThrow(); + return io->iface->getMode(io->data, &error); +} + +void nitf::IOInterface::close() +{ + nitf_IOInterface *io = getNativeOrThrow(); + io->iface->close(io->data, &error); +} diff --git a/modules/c++/nitf/source/ImageReader.cpp b/modules/c++/nitf/source/ImageReader.cpp new file mode 100644 index 000000000..8b5fede6b --- /dev/null +++ b/modules/c++/nitf/source/ImageReader.cpp @@ -0,0 +1,67 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/ImageReader.hpp" + +using namespace nitf; + +ImageReader::ImageReader(const ImageReader & x) +{ + setNative(x.getNative()); +} + +ImageReader & ImageReader::operator=(const ImageReader & x) +{ + if (&x != this) + setNative(x.getNative()); + return *this; +} + +ImageReader::ImageReader(nitf_ImageReader * x) +{ + setNative(x); + getNativeOrThrow(); +} + +ImageReader::~ImageReader(){} + +nitf::BlockingInfo ImageReader::getBlockingInfo() throw (nitf::NITFException) +{ + return nitf::BlockingInfo(nitf_ImageReader_getBlockingInfo(getNativeOrThrow(), &error)); +} + +void ImageReader::read(nitf::SubWindow & subWindow, nitf::Uint8 ** user, int * padded) throw (nitf::NITFException) +{ + NITF_BOOL x = nitf_ImageReader_read(getNativeOrThrow(), subWindow.getNative(), user, padded, &error); + if (!x) + throw nitf::NITFException(&error); +} + +const nitf::Uint8* ImageReader::readBlock(nitf::Uint32 blockNumber, nitf::Uint64* blockSize) +{ + return nitf_ImageReader_readBlock(getNativeOrThrow(), blockNumber, blockSize, &error); +} + +void ImageReader::setReadCaching() +{ + nitf_ImageReader_setReadCaching(getNativeOrThrow()); +} diff --git a/modules/c++/nitf/source/ImageSegment.cpp b/modules/c++/nitf/source/ImageSegment.cpp new file mode 100644 index 000000000..39ad89a4d --- /dev/null +++ b/modules/c++/nitf/source/ImageSegment.cpp @@ -0,0 +1,111 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/ImageSegment.hpp" + +using namespace nitf; + +ImageSegment::ImageSegment(const ImageSegment & x) +{ + setNative(x.getNative()); +} + +ImageSegment & ImageSegment::operator=(const ImageSegment & x) +{ + if (&x != this) + setNative(x.getNative()); + return *this; +} + +ImageSegment::ImageSegment(nitf_ImageSegment * x) +{ + setNative(x); + getNativeOrThrow(); +} + +ImageSegment::ImageSegment() throw(nitf::NITFException) +{ + setNative(nitf_ImageSegment_construct(&error)); + getNativeOrThrow(); + setManaged(false); +} + +ImageSegment::ImageSegment(NITF_DATA * x) +{ + setNative((nitf_ImageSegment*)x); + getNativeOrThrow(); +} + +ImageSegment & ImageSegment::operator=(NITF_DATA * x) +{ + setNative((nitf_ImageSegment*)x); + getNativeOrThrow(); + return *this; +} + + +nitf::ImageSegment ImageSegment::clone() throw(nitf::NITFException) +{ + nitf::ImageSegment dolly(nitf_ImageSegment_clone(getNativeOrThrow(), &error)); + dolly.setManaged(false); + return dolly; +} + +ImageSegment::~ImageSegment(){} + + +nitf::ImageSubheader ImageSegment::getSubheader() +{ + return nitf::ImageSubheader(getNativeOrThrow()->subheader); +} + + +void ImageSegment::setSubheader(nitf::ImageSubheader & value) +{ + //release the one currently "owned" + nitf::ImageSubheader sub = nitf::ImageSubheader(getNativeOrThrow()->subheader); + sub.setManaged(false); + + //have the library manage the "new" one + getNativeOrThrow()->subheader = value.getNative(); + value.setManaged(true); +} + +nitf::Uint64 ImageSegment::getImageOffset() const +{ + return getNativeOrThrow()->imageOffset; +} + +void ImageSegment::setImageOffset(nitf::Uint64 value) +{ + getNativeOrThrow()->imageOffset = value; +} + +nitf::Uint64 ImageSegment::getImageEnd() const +{ + return getNativeOrThrow()->imageEnd; +} + +void ImageSegment::setImageEnd(nitf::Uint64 value) +{ + getNativeOrThrow()->imageEnd = value; +} diff --git a/modules/c++/nitf/source/ImageSource.cpp b/modules/c++/nitf/source/ImageSource.cpp new file mode 100644 index 000000000..81007a51c --- /dev/null +++ b/modules/c++/nitf/source/ImageSource.cpp @@ -0,0 +1,86 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/ImageSource.hpp" + +using namespace nitf; + +ImageSource::ImageSource(const ImageSource & x) +{ + setNative(x.getNative()); +} + +ImageSource & ImageSource::operator=(const ImageSource & x) +{ + if (&x != this) + setNative(x.getNative()); + return *this; +} + +ImageSource::ImageSource(nitf_ImageSource * x) +{ + setNative(x); + getNativeOrThrow(); +} + +ImageSource::ImageSource() throw (nitf::NITFException) +{ + setNative(nitf_ImageSource_construct(&error)); + getNativeOrThrow(); + setManaged(false); +} + +ImageSource::~ImageSource() +{ + // //go through and delete all the attached bands + // for(std::vector::iterator it = mBands.begin(); + // it != mBands.end(); ++it) + // { + // (*it)->decRef(); + // delete *it; + // } +} + +void ImageSource::addBand(nitf::BandSource bandSource) + throw (nitf::NITFException) +{ + NITF_BOOL x = nitf_ImageSource_addBand(getNativeOrThrow(), + bandSource.getNativeOrThrow(), + &error); + if (!x) + throw nitf::NITFException(&error); + bandSource.setManaged(true); //the underlying memory is managed now + // mBands.push_back(bandSource); + // bandSource->incRef(); +} + +nitf::BandSource ImageSource::getBand(int n) throw (nitf::NITFException) +{ + nitf_DataSource * x = nitf_ImageSource_getBand(getNativeOrThrow(), n, + &error); + if (!x) + throw nitf::NITFException(&error); + + nitf::BandSource bandSource(x); + bandSource.setManaged(true); + return bandSource; +} diff --git a/modules/c++/nitf/source/ImageSubheader.cpp b/modules/c++/nitf/source/ImageSubheader.cpp new file mode 100644 index 000000000..c04136261 --- /dev/null +++ b/modules/c++/nitf/source/ImageSubheader.cpp @@ -0,0 +1,459 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/ImageSubheader.hpp" + +using namespace nitf; + +ImageSubheader::ImageSubheader(const ImageSubheader & x) +{ + setNative(x.getNative()); +} + +ImageSubheader & ImageSubheader::operator=(const ImageSubheader & x) +{ + if (&x != this) + setNative(x.getNative()); + return *this; +} + +ImageSubheader::ImageSubheader(nitf_ImageSubheader * x) +{ + setNative(x); + getNativeOrThrow(); +} + +ImageSubheader::ImageSubheader() throw(nitf::NITFException) +{ + setNative(nitf_ImageSubheader_construct(&error)); + getNativeOrThrow(); + setManaged(false); +} + + +nitf::ImageSubheader ImageSubheader::clone() throw(nitf::NITFException) +{ + nitf::ImageSubheader dolly(nitf_ImageSubheader_clone(getNativeOrThrow(), &error)); + dolly.setManaged(false); + return dolly; +} + +/*! + * Destructor + */ +ImageSubheader::~ImageSubheader(){} + + +void ImageSubheader::setPixelInformation(std::string pvtype, + nitf::Uint32 nbpp, + nitf::Uint32 abpp, + std::string justification, + std::string irep, std::string icat, + std::vector& bands) throw(nitf::NITFException) +{ + nitf::Uint32 bandCount = bands.size(); + nitf_BandInfo ** bandInfo = (nitf_BandInfo **)NITF_MALLOC( + sizeof(nitf_BandInfo*) * bandCount); + if (!bandInfo) + { + throw nitf::NITFException(Ctxt(FmtX("Out of Memory"))); + } + + for (nitf::Uint32 i = 0; i < bandCount; i++) + { + bandInfo[i] = nitf_BandInfo_clone(bands[i].getNative(), &error); + if (!bandInfo[i]) + throw nitf::NITFException(&error); + } + + NITF_BOOL x = nitf_ImageSubheader_setPixelInformation(getNativeOrThrow(), + pvtype.c_str(), nbpp, abpp, justification.c_str(), irep.c_str(), + icat.c_str(), bandCount, bandInfo, &error); + if (!x) + throw nitf::NITFException(&error); +} + + +void ImageSubheader::setPixelInformation(std::string pvtype, + nitf::Uint32 nbpp, + nitf::Uint32 abpp, + std::string justification, + std::string irep, std::string icat, + nitf::Uint32 bandCount, + std::vector& bands) throw(nitf::NITFException) +{ + return setPixelInformation(pvtype, nbpp, abpp, justification, irep, icat, + bands); +} + +void ImageSubheader::setBlocking(nitf::Uint32 numRows, + nitf::Uint32 numCols, + nitf::Uint32 numRowsPerBlock, + nitf::Uint32 numColsPerBlock, + const std::string& imode) throw(nitf::NITFException) +{ + NITF_BOOL x = nitf_ImageSubheader_setBlocking(getNativeOrThrow(), + numRows, numCols, numRowsPerBlock, numColsPerBlock, imode.c_str(), + &error); + if (!x) + throw nitf::NITFException(&error); +} + +void ImageSubheader::computeBlocking(nitf::Uint32 numRows, + nitf::Uint32 numCols, + nitf::Uint32& numRowsPerBlock, + nitf::Uint32& numColsPerBlock, + nitf::Uint32& numBlocksPerCol, + nitf::Uint32& numBlocksPerRow) +{ + nitf_ImageSubheader_computeBlocking(numRows, + numCols, + &numRowsPerBlock, + &numColsPerBlock, + &numBlocksPerCol, + &numBlocksPerRow); +} + +void ImageSubheader::setDimensions(nitf::Uint32 numRows, nitf::Uint32 numCols) + throw(nitf::NITFException) +{ + NITF_BOOL x = nitf_ImageSubheader_setDimensions(getNativeOrThrow(), + numRows, numCols, &error); + if (!x) + throw nitf::NITFException(&error); +} + +nitf::Uint32 ImageSubheader::getBandCount() throw(nitf::NITFException) +{ + nitf::Uint32 x = nitf_ImageSubheader_getBandCount(getNativeOrThrow(), &error); + if (x == NITF_INVALID_BAND_COUNT) + throw nitf::NITFException(&error); + return x; +} + +void ImageSubheader::createBands(nitf::Uint32 numBands) throw(nitf::NITFException) +{ + if (!nitf_ImageSubheader_createBands(getNativeOrThrow(), numBands, &error)) + throw nitf::NITFException(&error); +} + + +void ImageSubheader::setCornersFromLatLons(nitf::CornersType type, + double corners[4][2]) + throw(nitf::NITFException) +{ + NITF_BOOL x = nitf_ImageSubheader_setCornersFromLatLons(getNativeOrThrow(), + type, + corners, + &error); + if (!x) + throw nitf::NITFException(&error); + +} + +void ImageSubheader::getCornersAsLatLons(double corners[4][2]) + throw(nitf::NITFException) +{ + NITF_BOOL x = nitf_ImageSubheader_getCornersAsLatLons(getNativeOrThrow(), + corners, + &error); + if (!x) + throw nitf::NITFException(&error); + +} + +nitf::CornersType ImageSubheader::getCornersType() + throw(nitf::NITFException) +{ + return nitf_ImageSubheader_getCornersType(getNativeOrThrow()); +} + +int ImageSubheader::insertImageComment(std::string comment, int index) +{ + int actualIndex = nitf_ImageSubheader_insertImageComment(getNativeOrThrow(), + (char*)comment.c_str(), index, &error); + if (actualIndex < 0) + throw nitf::NITFException(&error); + return actualIndex; +} + + +void ImageSubheader::removeImageComment(int index) +{ + NITF_BOOL x = nitf_ImageSubheader_removeImageComment(getNativeOrThrow(), + index, &error); + if (!x) + throw nitf::NITFException(&error); +} + + +nitf::Field ImageSubheader::getFilePartType() +{ + return nitf::Field(getNativeOrThrow()->filePartType); +} + +nitf::Field ImageSubheader::getImageId() +{ + return nitf::Field(getNativeOrThrow()->imageId); +} + +nitf::Field ImageSubheader::getImageDateAndTime() +{ + return nitf::Field(getNativeOrThrow()->imageDateAndTime); +} + +nitf::Field ImageSubheader::getTargetId() +{ + return nitf::Field(getNativeOrThrow()->targetId); +} + +nitf::Field ImageSubheader::getImageTitle() +{ + return nitf::Field(getNativeOrThrow()->imageTitle); +} + +nitf::Field ImageSubheader::getImageSecurityClass() +{ + return nitf::Field(getNativeOrThrow()->imageSecurityClass); +} + +nitf::FileSecurity ImageSubheader::getSecurityGroup() +{ + return nitf::FileSecurity(getNativeOrThrow()->securityGroup); +} + +void ImageSubheader::setSecurityGroup(nitf::FileSecurity value) +{ + //release the owned security group + nitf::FileSecurity fs = nitf::FileSecurity(getNativeOrThrow()->securityGroup); + fs.setManaged(false); + + //have the library manage the new securitygroup + getNativeOrThrow()->securityGroup = value.getNative(); + value.setManaged(true); +} + +nitf::Field ImageSubheader::getEncrypted() +{ + return nitf::Field(getNativeOrThrow()->encrypted); +} + +nitf::Field ImageSubheader::getImageSource() +{ + return nitf::Field(getNativeOrThrow()->imageSource); +} + +nitf::Field ImageSubheader::getNumRows() +{ + return nitf::Field(getNativeOrThrow()->numRows); +} + +nitf::Field ImageSubheader::getNumCols() +{ + return nitf::Field(getNativeOrThrow()->numCols); +} + +nitf::Field ImageSubheader::getPixelValueType() +{ + return nitf::Field(getNativeOrThrow()->pixelValueType); +} + +nitf::Field ImageSubheader::getImageRepresentation() +{ + return nitf::Field(getNativeOrThrow()->imageRepresentation); +} + +nitf::Field ImageSubheader::getImageCategory() +{ + return nitf::Field(getNativeOrThrow()->imageCategory); +} + +nitf::Field ImageSubheader::getActualBitsPerPixel() +{ + return nitf::Field(getNativeOrThrow()->actualBitsPerPixel); +} + +nitf::Field ImageSubheader::getPixelJustification() +{ + return nitf::Field(getNativeOrThrow()->pixelJustification); +} + +nitf::Field ImageSubheader::getImageCoordinateSystem() +{ + return nitf::Field(getNativeOrThrow()->imageCoordinateSystem); +} + +nitf::Field ImageSubheader::getCornerCoordinates() +{ + return nitf::Field(getNativeOrThrow()->cornerCoordinates); +} + +nitf::Field ImageSubheader::getNumImageComments() +{ + return nitf::Field(getNativeOrThrow()->numImageComments); +} + +nitf::List ImageSubheader::getImageComments() +{ + return nitf::List(getNativeOrThrow()->imageComments); +} + +nitf::Field ImageSubheader::getImageCompression() +{ + return nitf::Field(getNativeOrThrow()->imageCompression); +} + +nitf::Field ImageSubheader::getCompressionRate() +{ + return nitf::Field(getNativeOrThrow()->compressionRate); +} + +nitf::Field ImageSubheader::getNumImageBands() +{ + return nitf::Field(getNativeOrThrow()->numImageBands); +} + +nitf::Field ImageSubheader::getNumMultispectralImageBands() +{ + return nitf::Field(getNativeOrThrow()->numMultispectralImageBands); +} + +nitf::BandInfo ImageSubheader::getBandInfo(nitf::Uint32 band) throw(nitf::NITFException) +{ + return nitf::BandInfo(nitf_ImageSubheader_getBandInfo( + getNativeOrThrow(), band, &error)); +} + +nitf::Field ImageSubheader::getImageSyncCode() +{ + return nitf::Field(getNativeOrThrow()->imageSyncCode); +} + +nitf::Field ImageSubheader::getImageMode() +{ + return nitf::Field(getNativeOrThrow()->imageMode); +} + +nitf::Field ImageSubheader::getNumBlocksPerRow() +{ + return nitf::Field(getNativeOrThrow()->numBlocksPerRow); +} + +nitf::Field ImageSubheader::getNumBlocksPerCol() +{ + return nitf::Field(getNativeOrThrow()->numBlocksPerCol); +} + +nitf::Field ImageSubheader::getNumPixelsPerHorizBlock() +{ + return nitf::Field(getNativeOrThrow()->numPixelsPerHorizBlock); +} + +nitf::Field ImageSubheader::getNumPixelsPerVertBlock() +{ + return nitf::Field(getNativeOrThrow()->numPixelsPerVertBlock); +} + +nitf::Field ImageSubheader::getNumBitsPerPixel() +{ + return nitf::Field(getNativeOrThrow()->numBitsPerPixel); +} + +nitf::Field ImageSubheader::getImageDisplayLevel() +{ + return nitf::Field(getNativeOrThrow()->imageDisplayLevel); +} + +nitf::Field ImageSubheader::getImageAttachmentLevel() +{ + return nitf::Field(getNativeOrThrow()->imageAttachmentLevel); +} + +nitf::Field ImageSubheader::getImageLocation() +{ + return nitf::Field(getNativeOrThrow()->imageLocation); +} + +nitf::Field ImageSubheader::getImageMagnification() +{ + return nitf::Field(getNativeOrThrow()->imageMagnification); +} + +nitf::Field ImageSubheader::getUserDefinedImageDataLength() +{ + return nitf::Field(getNativeOrThrow()->userDefinedImageDataLength); +} + +nitf::Field ImageSubheader::getUserDefinedOverflow() +{ + return nitf::Field(getNativeOrThrow()->userDefinedOverflow); +} + +nitf::Field ImageSubheader::getExtendedHeaderLength() +{ + return nitf::Field(getNativeOrThrow()->extendedHeaderLength); +} + +nitf::Field ImageSubheader::getExtendedHeaderOverflow() +{ + return nitf::Field(getNativeOrThrow()->extendedHeaderOverflow); +} + +nitf::Extensions ImageSubheader::getUserDefinedSection() +{ + return nitf::Extensions(getNativeOrThrow()->userDefinedSection); +} + +void ImageSubheader::setUserDefinedSection(nitf::Extensions value) +{ + if (getNativeOrThrow()->userDefinedSection) + { + //release the one currently "owned", if different + nitf::Extensions exts = nitf::Extensions(getNativeOrThrow()->userDefinedSection); + if (exts != value) + exts.setManaged(false); + } + + //have the library manage the "new" one + getNativeOrThrow()->userDefinedSection = value.getNative(); + value.setManaged(true); +} + +nitf::Extensions ImageSubheader::getExtendedSection() +{ + return nitf::Extensions(getNativeOrThrow()->extendedSection); +} + +void ImageSubheader::setExtendedSection(nitf::Extensions value) +{ + if (getNativeOrThrow()->extendedSection) + { + //release the one currently "owned", if different + nitf::Extensions exts = nitf::Extensions(getNativeOrThrow()->extendedSection); + if (exts != value) + exts.setManaged(false); + } + + //have the library manage the "new" one + getNativeOrThrow()->extendedSection = value.getNative(); + value.setManaged(true); +} diff --git a/modules/c++/nitf/source/ImageWriter.cpp b/modules/c++/nitf/source/ImageWriter.cpp new file mode 100644 index 000000000..e2c64a0dd --- /dev/null +++ b/modules/c++/nitf/source/ImageWriter.cpp @@ -0,0 +1,68 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/ImageWriter.hpp" + +using namespace nitf; + +ImageWriter::ImageWriter(nitf::ImageSubheader& subheader) + throw (nitf::NITFException) +{ + setNative(nitf_ImageWriter_construct(subheader.getNative(), NULL, &error)); +} + +ImageWriter::~ImageWriter() +{ + // if (mAdopt && mImageSource) + // { + // mImageSource->decRef(); + // delete mImageSource; + // } +} + +void ImageWriter::attachSource(nitf::ImageSource imageSource) + throw (nitf::NITFException) +{ + if (!nitf_ImageWriter_attachSource(getNativeOrThrow(), + imageSource.getNative(), &error)) + throw nitf::NITFException(&error); + imageSource.setManaged(true); + // imageSource->incRef(); + // mImageSource = imageSource; + // mAdopt = adopt; +} + +void ImageWriter::setWriteCaching(int enable) +{ + nitf_ImageWriter_setWriteCaching(getNativeOrThrow(), enable); +} + +void ImageWriter::setDirectBlockWrite(int enable) +{ + nitf_ImageWriter_setDirectBlockWrite(getNativeOrThrow(), enable); +} + +void ImageWriter::setPadPixel(nitf::Uint8* value, nitf::Uint32 length) +{ + if (!nitf_ImageWriter_setPadPixel(getNativeOrThrow(), value, length, &error)) + throw nitf::NITFException(&error); +} diff --git a/modules/c++/nitf/source/LabelSegment.cpp b/modules/c++/nitf/source/LabelSegment.cpp new file mode 100644 index 000000000..c87ad7653 --- /dev/null +++ b/modules/c++/nitf/source/LabelSegment.cpp @@ -0,0 +1,111 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/LabelSegment.hpp" + +using namespace nitf; + +LabelSegment::LabelSegment(const LabelSegment & x) +{ + setNative(x.getNative()); +} + +LabelSegment & LabelSegment::operator=(const LabelSegment & x) +{ + if (&x != this) + setNative(x.getNative()); + return *this; +} + +LabelSegment::LabelSegment(nitf_LabelSegment * x) +{ + setNative(x); + getNativeOrThrow(); +} + +LabelSegment::LabelSegment() throw(nitf::NITFException) +{ + setNative(nitf_LabelSegment_construct(&error)); + getNativeOrThrow(); + setManaged(false); +} + +LabelSegment::LabelSegment(NITF_DATA * x) +{ + setNative((nitf_LabelSegment*)x); + getNativeOrThrow(); +} + +LabelSegment & LabelSegment::operator=(NITF_DATA * x) +{ + setNative((nitf_LabelSegment*)x); + getNativeOrThrow(); + return *this; +} + + +nitf::LabelSegment LabelSegment::clone() throw(nitf::NITFException) +{ + nitf::LabelSegment dolly( + nitf_LabelSegment_clone(getNativeOrThrow(), &error)); + dolly.setManaged(false); + return dolly; +} + +LabelSegment::~LabelSegment(){} + +nitf::LabelSubheader LabelSegment::getSubheader() +{ + return nitf::LabelSubheader(getNativeOrThrow()->subheader); +} + +void LabelSegment::setSubheader(nitf::LabelSubheader & value) +{ + //release the one currently "owned" + nitf::LabelSubheader sub = nitf::LabelSubheader(getNativeOrThrow()->subheader); + sub.setManaged(false); + + //have the library manage the "new" one + getNativeOrThrow()->subheader = value.getNative(); + value.setManaged(true); +} + +nitf::Uint64 LabelSegment::getOffset() const +{ + return getNativeOrThrow()->offset; +} + +void LabelSegment::setOffset(nitf::Uint64 value) +{ + getNativeOrThrow()->offset = value; +} + +nitf::Uint64 LabelSegment::getEnd() const +{ + return getNativeOrThrow()->end; +} + +void LabelSegment::setEnd(nitf::Uint64 value) +{ + getNativeOrThrow()->end = value; +} + diff --git a/modules/c++/nitf/source/LabelSubheader.cpp b/modules/c++/nitf/source/LabelSubheader.cpp new file mode 100644 index 000000000..8cd219edd --- /dev/null +++ b/modules/c++/nitf/source/LabelSubheader.cpp @@ -0,0 +1,173 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/LabelSubheader.hpp" + +using namespace nitf; + +LabelSubheader::LabelSubheader(const LabelSubheader & x) +{ + setNative(x.getNative()); +} + +LabelSubheader & LabelSubheader::operator=(const LabelSubheader & x) +{ + if (&x != this) + setNative(x.getNative()); + return *this; +} + +LabelSubheader::LabelSubheader(nitf_LabelSubheader * x) +{ + setNative(x); + getNativeOrThrow(); +} + +LabelSubheader::LabelSubheader() throw(nitf::NITFException) +{ + setNative(nitf_LabelSubheader_construct(&error)); + getNativeOrThrow(); + setManaged(false); +} + + +LabelSubheader LabelSubheader::clone() throw(nitf::NITFException) +{ + nitf::LabelSubheader dolly( + nitf_LabelSubheader_clone(getNativeOrThrow(), &error)); + dolly.setManaged(false); + return dolly; +} + +LabelSubheader::~LabelSubheader(){} + + +nitf::Field LabelSubheader::getFilePartType() +{ + return nitf::Field(getNativeOrThrow()->filePartType); +} + +nitf::Field LabelSubheader::getLabelID() +{ + return nitf::Field(getNativeOrThrow()->labelID); +} + +nitf::Field LabelSubheader::getSecurityClass() +{ + return nitf::Field(getNativeOrThrow()->securityClass); +} + +nitf::FileSecurity LabelSubheader::getSecurityGroup() +{ + return nitf::FileSecurity(getNativeOrThrow()->securityGroup); +} + +void LabelSubheader::setSecurityGroup(nitf::FileSecurity value) +{ + //release the owned security group + nitf::FileSecurity fs = nitf::FileSecurity(getNativeOrThrow()->securityGroup); + fs.setManaged(false); + + //have the library manage the new securitygroup + getNativeOrThrow()->securityGroup = value.getNative(); + value.setManaged(true); +} + +nitf::Field LabelSubheader::getEncrypted() +{ + return nitf::Field(getNativeOrThrow()->encrypted); +} + +nitf::Field LabelSubheader::getFontStyle() +{ + return nitf::Field(getNativeOrThrow()->fontStyle); +} + +nitf::Field LabelSubheader::getCellWidth() +{ + return nitf::Field(getNativeOrThrow()->cellWidth); +} + +nitf::Field LabelSubheader::getCellHeight() +{ + return nitf::Field(getNativeOrThrow()->cellHeight); +} + +nitf::Field LabelSubheader::getDisplayLevel() +{ + return nitf::Field(getNativeOrThrow()->displayLevel); +} + +nitf::Field LabelSubheader::getAttachmentLevel() +{ + return nitf::Field(getNativeOrThrow()->attachmentLevel); +} + +nitf::Field LabelSubheader::getLocationRow() +{ + return nitf::Field(getNativeOrThrow()->locationRow); +} + +nitf::Field LabelSubheader::getLocationColumn() +{ + return nitf::Field(getNativeOrThrow()->locationColumn); +} + +nitf::Field LabelSubheader::getTextColor() +{ + return nitf::Field(getNativeOrThrow()->textColor); +} + +nitf::Field LabelSubheader::getBackgroundColor() +{ + return nitf::Field(getNativeOrThrow()->backgroundColor); +} + +nitf::Field LabelSubheader::getExtendedHeaderLength() +{ + return nitf::Field(getNativeOrThrow()->extendedHeaderLength); +} + +nitf::Field LabelSubheader::getExtendedHeaderOverflow() +{ + return nitf::Field(getNativeOrThrow()->extendedHeaderOverflow); +} + +nitf::Extensions LabelSubheader::getExtendedSection() +{ + return nitf::Extensions(getNativeOrThrow()->extendedSection); +} + +void LabelSubheader::setExtendedSection(nitf::Extensions value) +{ + if (getNativeOrThrow()->extendedSection) + { + //release the one currently "owned", if different + nitf::Extensions exts = nitf::Extensions(getNativeOrThrow()->extendedSection); + if (exts != value) + exts.setManaged(false); + } + + //have the library manage the "new" one + getNativeOrThrow()->extendedSection = value.getNative(); + value.setManaged(true); +} diff --git a/modules/c++/nitf/source/List.cpp b/modules/c++/nitf/source/List.cpp new file mode 100644 index 000000000..b5d99fd3f --- /dev/null +++ b/modules/c++/nitf/source/List.cpp @@ -0,0 +1,238 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/List.hpp" + +/////////////////////////////////////////////////////////////////////////////// +// ListNode + +nitf::ListNode & nitf::ListNode::operator=(const nitf::ListNode & x) +{ + if (&x != this) + setNative(x.getNative()); + return *this; +} + +nitf::ListNode::ListNode(nitf_ListNode * x) +{ + setNative(x); + getNativeOrThrow(); +} + +nitf::ListNode::ListNode(nitf::ListNode & prev, nitf::ListNode & next, NITF_DATA* data) + throw(nitf::NITFException) +{ + setNative(nitf_ListNode_construct(prev.getNative(), + next.getNative(), data, &error)); + getNativeOrThrow(); + setManaged(false); +} + +NITF_DATA * nitf::ListNode::getData() const +{ + return getNativeOrThrow()->data; +} + +void nitf::ListNode::setData(NITF_DATA * value) +{ + getNativeOrThrow()->data = value; +} + +/////////////////////////////////////////////////////////////////////////////// +// ListIterator + +nitf::ListIterator & nitf::ListIterator::operator=(const nitf::ListIterator & x) +{ + if (&x != this) + { + handle = x.handle; + setMembers(); + } + return *this; +} + +nitf::ListIterator::ListIterator(nitf_ListIterator x) { setHandle(x); } + +nitf_ListIterator & nitf::ListIterator::getHandle() { return handle; } + +bool nitf::ListIterator::equals(nitf::ListIterator& it2) +{ + NITF_BOOL x = nitf_ListIterator_equals(&handle, &it2.getHandle()); + if (!x) return false; + return true; +} + +bool nitf::ListIterator::operator==(const nitf::ListIterator& it2) +{ + return this->equals((nitf::ListIterator&)it2); +} + +bool nitf::ListIterator::notEqualTo(nitf::ListIterator& it2) +{ + NITF_BOOL x = nitf_ListIterator_notEqualTo(&handle, &it2.getHandle()); + if (!x) return false; + return true; +} + +bool nitf::ListIterator::operator!=(const nitf::ListIterator& it2) +{ + return this->notEqualTo((nitf::ListIterator&)it2); +} + +void nitf::ListIterator::increment() +{ + nitf_ListIterator_increment(&handle); + setMembers(); +} + +void nitf::ListIterator::operator++(int x) { increment(); } + +nitf::ListIterator & nitf::ListIterator::operator+=(int x) +{ + for (int i = 0; i < x; ++i) + increment(); + return *this; +} + +nitf::ListIterator nitf::ListIterator::operator+(int x) +{ + nitf::ListIterator it = nitf::ListIterator(*this); + it += x; + return it; +} + +/////////////////////////////////////////////////////////////////////////////// +// List + +nitf::List::List(const nitf::List & x) +{ + setNative(x.getNative()); +} + +nitf::List & nitf::List::operator=(const nitf::List & x) +{ + if (&x != this) + setNative(x.getNative()); + return *this; +} + +nitf::List::List(nitf_List * x) +{ + setNative(x); + getNativeOrThrow(); +} + +bool nitf::List::isEmpty() +{ + NITF_BOOL x = nitf_List_isEmpty(getNativeOrThrow()); + return x ? true : false; +} + +void nitf::List::pushFront(NITF_DATA* data) throw(nitf::NITFException) +{ + NITF_BOOL x = nitf_List_pushFront(getNativeOrThrow(), data, &error); + if (!x) + throw nitf::NITFException(&error); +} + +void nitf::List::pushBack(NITF_DATA* data) throw(nitf::NITFException) +{ + NITF_BOOL x = nitf_List_pushBack(getNativeOrThrow(), data, &error); + if (!x) + throw nitf::NITFException(&error); +} + +NITF_DATA* nitf::List::popFront() +{ + NITF_DATA * data = nitf_List_popFront(getNativeOrThrow()); + return data; +} + +NITF_DATA* nitf::List::popBack() +{ + NITF_DATA * data = nitf_List_popBack(getNativeOrThrow()); + return data; +} + +nitf::List::List() throw(nitf::NITFException) +{ + setNative(nitf_List_construct(&error)); + getNativeOrThrow(); + setManaged(false); +} + +nitf::List nitf::List::clone(NITF_DATA_ITEM_CLONE cloner) throw(nitf::NITFException) +{ + nitf::List dolly(nitf_List_clone(getNativeOrThrow(), cloner, &error)); + dolly.setManaged(false); + return dolly; +} + +nitf::List::~List(){} + +nitf::ListIterator nitf::List::begin() +{ + nitf_ListIterator x = nitf_List_begin(getNativeOrThrow()); + return nitf::ListIterator(x); +} + +nitf::ListIterator nitf::List::end() +{ + nitf_ListIterator x = nitf_List_end(getNativeOrThrow()); + return nitf::ListIterator(x); +} + +void nitf::List::insert(nitf::ListIterator & iter, NITF_DATA* data) throw(nitf::NITFException) +{ + NITF_BOOL x = nitf_List_insert(getNativeOrThrow(), iter.getHandle(), data, &error); + if (!x) + throw nitf::NITFException(&error); +} + +NITF_DATA* nitf::List::remove(nitf::ListIterator & where) +{ + NITF_DATA * data = nitf_List_remove(getNativeOrThrow(), &where.getHandle()); + return data; +} + +nitf::ListNode nitf::List::getFirst() +{ + return nitf::ListNode(getNativeOrThrow()->first); +} + +nitf::ListNode nitf::List::getLast() +{ + return nitf::ListNode(getNativeOrThrow()->last); +} + +size_t nitf::List::getSize() +{ + return (size_t)nitf_List_size(getNativeOrThrow()); +} + +NITF_DATA* nitf::List::operator[] (size_t index) throw(nitf::NITFException) +{ + NITF_DATA* x = nitf_List_get(getNativeOrThrow(), index, &error); + if (!x) + throw nitf::NITFException(&error); + return x; +} diff --git a/modules/c++/nitf/source/LookupTable.cpp b/modules/c++/nitf/source/LookupTable.cpp new file mode 100644 index 000000000..cd8927d21 --- /dev/null +++ b/modules/c++/nitf/source/LookupTable.cpp @@ -0,0 +1,98 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/LookupTable.hpp" + +using namespace nitf; + +LookupTable::LookupTable(size_t numTables, size_t numEntries) +{ + nitf_LookupTable* const lookupTable = + nitf_LookupTable_construct(numTables, numEntries, &error); + if (!lookupTable) + { + throw nitf::NITFException(&error); + + } + setNative(lookupTable); +} + +LookupTable::LookupTable(const unsigned char* table, + size_t numTables, + size_t numEntries) +{ + nitf_LookupTable* const lookupTable = + nitf_LookupTable_construct(numTables, numEntries, &error); + if (!lookupTable) + { + throw nitf::NITFException(&error); + + } + setNative(lookupTable); + setTable(table, numTables, numEntries); +} + +LookupTable::LookupTable(const LookupTable & x) +{ + setNative(x.getNative()); +} + +LookupTable & LookupTable::operator=(const LookupTable & x) +{ + if (&x != this) + setNative(x.getNative()); + return *this; +} + +LookupTable::LookupTable(nitf_LookupTable * x) +{ + setNative(x); + getNativeOrThrow(); +} + +LookupTable::~LookupTable() {} + +size_t LookupTable::getTables() const +{ + return getNativeOrThrow()->tables; +} + +size_t LookupTable::getEntries() const +{ + return getNativeOrThrow()->entries; +} + +unsigned char * LookupTable::getTable() const +{ + return getNativeOrThrow()->table; +} + +void LookupTable::setTable(const unsigned char *table, + size_t numTables, + size_t numEntries) +{ + if (!nitf_LookupTable_init(getNativeOrThrow(), numTables, + numEntries, table, &error)) + { + throw nitf::NITFException(&error); + } +} diff --git a/modules/c++/nitf/source/Makefile.in b/modules/c++/nitf/source/Makefile.in new file mode 100644 index 000000000..554eda817 --- /dev/null +++ b/modules/c++/nitf/source/Makefile.in @@ -0,0 +1,56 @@ +# ========================================================================= +# This file is part of NITRO +# ========================================================================= +# +# (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems +# +# NITRO is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, If not, +# see . +# + +#---------------------------------------- +# This is for project-specific stuff +#---------------------------------------- +include ../build/Makefile + +#---------------------------------------- +# Build commands +#---------------------------------------- +OBJS = ${SOURCES:.cpp=.o} +#---------------------------------------- +# Just lib, which requires objects +#---------------------------------------- +$(LIBDIR)/$(LIBNAME): $(OBJS) dirs + $(ARCHIVE) $(LIBDIR)/$(LIBNAME) $(OBJS) + +#---------------------------------------- +# Rule for setting up dir. structure +#---------------------------------------- +dirs: + \mkdir -p $(LIBDIR) + +#---------------------------------------- +# Rule for building C++ objects +#---------------------------------------- +.SUFFIXES: .o .cpp +.cpp.o: + $(COMPILE) -c $? + +clean: + \rm -f $(OBJS) + \rm -rf $(LIBDIR) + +raw: clean + \rm -f Makefile + diff --git a/modules/c++/nitf/source/MemoryIO.cpp b/modules/c++/nitf/source/MemoryIO.cpp new file mode 100644 index 000000000..f80d65b97 --- /dev/null +++ b/modules/c++/nitf/source/MemoryIO.cpp @@ -0,0 +1,63 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + +namespace nitf +{ +nitf_IOInterface* MemoryIO::create(void* buffer, + size_t size, + bool adopt) throw(nitf::NITFException) +{ + nitf_Error error; + nitf_IOInterface* const interface = nitf_BufferAdapter_construct( + static_cast(buffer), size, adopt, &error); + + if (!interface) + { + if (adopt) + { + // It's our job to free this now + NRT_FREE(buffer); + } + throw nitf::NITFException(&error); + } + + return interface; +} + +MemoryIO::MemoryIO(size_t capacity) throw(nitf::NITFException) : + IOInterface(create(NRT_MALLOC(capacity), capacity, true)) +{ + // NOTE: We are telling the C layer to adopt this memory which means it + // will use NRT_FREE() to deallocate it. So, we must allocate with + // NRT_MALLOC(). + setManaged(false); +} + +MemoryIO::MemoryIO(void* buffer, size_t size, bool adopt) + throw(nitf::NITFException) : + IOInterface(create(buffer, size, adopt)) +{ + setManaged(false); +} +} diff --git a/modules/c++/nitf/source/PluginRegistry.cpp b/modules/c++/nitf/source/PluginRegistry.cpp new file mode 100644 index 000000000..90e20557c --- /dev/null +++ b/modules/c++/nitf/source/PluginRegistry.cpp @@ -0,0 +1,63 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/PluginRegistry.hpp" + +namespace nitf +{ +void PluginRegistry::loadDir(const std::string& dirName) throw(NITFException) +{ + nitf_Error error; + if (!nitf_PluginRegistry_loadDir(dirName.c_str(), &error)) + throw NITFException(&error); +} + +void PluginRegistry::loadPlugin(const std::string& path) throw(NITFException) +{ + nitf_Error error; + if (!nitf_PluginRegistry_loadPlugin(path.c_str(), &error)) + throw NITFException(&error); +} + +void PluginRegistry::registerTREHandler(NITF_PLUGIN_INIT_FUNCTION init, + NITF_PLUGIN_TRE_HANDLER_FUNCTION handler) + throw(NITFException) +{ + nitf_Error error; + if (!nitf_PluginRegistry_registerTREHandler(init, handler, &error)) + throw NITFException(&error); +} + +nitf_CompressionInterface* PluginRegistry::retrieveCompressionInterface( + const std::string& comp) throw(NITFException) +{ + nitf_Error error; + nitf_CompressionInterface* const compIface = + nitf_PluginRegistry_retrieveCompInterface(comp.c_str(), &error); + if (compIface == NULL) + { + throw NITFException(&error); + } + + return compIface; +} +} diff --git a/modules/c++/nitf/source/RESegment.cpp b/modules/c++/nitf/source/RESegment.cpp new file mode 100644 index 000000000..e06b04651 --- /dev/null +++ b/modules/c++/nitf/source/RESegment.cpp @@ -0,0 +1,109 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/RESegment.hpp" + +using namespace nitf; + +RESegment::RESegment(const RESegment & x) +{ + setNative(x.getNative()); +} + +RESegment & RESegment::operator=(const RESegment & x) +{ + if (&x != this) + setNative(x.getNative()); + return *this; +} + +RESegment::RESegment(nitf_RESegment * x) +{ + setNative(x); + getNativeOrThrow(); +} + +RESegment::RESegment() throw(nitf::NITFException) +{ + setNative(nitf_RESegment_construct(&error)); + getNativeOrThrow(); + setManaged(false); +} + +RESegment::RESegment(NITF_DATA * x) +{ + setNative((nitf_RESegment*)x); + getNativeOrThrow(); +} + +RESegment & RESegment::operator=(NITF_DATA * x) +{ + setNative((nitf_RESegment*)x); + getNativeOrThrow(); + return *this; +} + +nitf::RESegment RESegment::clone() throw(nitf::NITFException) +{ + nitf::RESegment dolly( + nitf_RESegment_clone(getNativeOrThrow(), &error)); + dolly.setManaged(false); + return dolly; +} + +RESegment::~RESegment(){} + +nitf::RESubheader RESegment::getSubheader() +{ + return nitf::RESubheader(getNativeOrThrow()->subheader); +} + +void RESegment::setSubheader(nitf::RESubheader & value) +{ + //release the one currently "owned" + nitf::RESubheader sub = nitf::RESubheader(getNativeOrThrow()->subheader); + sub.setManaged(false); + + //have the library manage the "new" one + getNativeOrThrow()->subheader = value.getNative(); + value.setManaged(true); +} + +nitf::Uint64 RESegment::getOffset() const +{ + return getNativeOrThrow()->offset; +} + +void RESegment::setOffset(nitf::Uint64 value) +{ + getNativeOrThrow()->offset = value; +} + +nitf::Uint64 RESegment::getEnd() const +{ + return getNativeOrThrow()->end; +} + +void RESegment::setEnd(nitf::Uint64 value) +{ + getNativeOrThrow()->end = value; +} diff --git a/modules/c++/nitf/source/RESubheader.cpp b/modules/c++/nitf/source/RESubheader.cpp new file mode 100644 index 000000000..616de347f --- /dev/null +++ b/modules/c++/nitf/source/RESubheader.cpp @@ -0,0 +1,118 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/RESubheader.hpp" + +using namespace nitf; + +RESubheader::RESubheader(const RESubheader & x) +{ + setNative(x.getNative()); +} + +RESubheader & RESubheader::operator=(const RESubheader & x) +{ + if (&x != this) + setNative(x.getNative()); + return *this; +} + +RESubheader::RESubheader(nitf_RESubheader * x) +{ + setNative(x); + getNativeOrThrow(); +} + +RESubheader::RESubheader() throw(nitf::NITFException) +{ + setNative(nitf_RESubheader_construct(&error)); + getNativeOrThrow(); + setManaged(false); +} + + +nitf::RESubheader RESubheader::clone() throw(nitf::NITFException) +{ + nitf::RESubheader dolly( + nitf_RESubheader_clone(getNativeOrThrow(), &error)); + dolly.setManaged(false); + return dolly; +} + +RESubheader::~RESubheader(){} + + +nitf::Field RESubheader::getFilePartType() +{ + return nitf::Field(getNativeOrThrow()->filePartType); +} + +nitf::Field RESubheader::getTypeID() +{ + return nitf::Field(getNativeOrThrow()->typeID); +} + +nitf::Field RESubheader::getVersion() +{ + return nitf::Field(getNativeOrThrow()->version); +} + +nitf::Field RESubheader::getSecurityClass() +{ + return nitf::Field(getNativeOrThrow()->securityClass); +} + +nitf::FileSecurity RESubheader::getSecurityGroup() +{ + return nitf::FileSecurity(getNativeOrThrow()->securityGroup); +} + +void RESubheader::setSecurityGroup(nitf::FileSecurity value) +{ + //release the owned security group + nitf::FileSecurity fs = nitf::FileSecurity(getNativeOrThrow()->securityGroup); + fs.setManaged(false); + + //have the library manage the new securitygroup + getNativeOrThrow()->securityGroup = value.getNative(); + value.setManaged(true); +} + +nitf::Field RESubheader::getSubheaderFieldsLength() +{ + return nitf::Field(getNativeOrThrow()->subheaderFieldsLength); +} + +char * RESubheader::getSubheaderFields() const +{ + return getNativeOrThrow()->subheaderFields; +} + +nitf::Uint64 RESubheader::getDataLength() const +{ + return getNativeOrThrow()->dataLength; +} + +void RESubheader::setDataLength(nitf::Uint32 value) +{ + getNativeOrThrow()->dataLength = value; +} diff --git a/modules/c++/nitf/source/Reader.cpp b/modules/c++/nitf/source/Reader.cpp new file mode 100644 index 000000000..2640dd69e --- /dev/null +++ b/modules/c++/nitf/source/Reader.cpp @@ -0,0 +1,227 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/Reader.hpp" + +using namespace nitf; + +void ReaderDestructor::operator()(nitf_Reader *reader) +{ + if (reader) + { + if (reader->record) + { + // this tells the handle manager that the Record is no longer managed + nitf::Record rec(reader->record); + rec.setManaged(false); + } + if (reader->input && !reader->ownInput) + { + // this tells the handle manager that the IOInterface is no longer managed + nitf::IOInterface io(reader->input); + io.setManaged(false); + } + nitf_Reader_destruct(&reader); + } +} + +Reader::Reader(const Reader & x) +{ + setNative(x.getNative()); +} + +Reader & Reader::operator=(const Reader & x) +{ + if (&x != this) + setNative(x.getNative()); + return *this; +} + +Reader::Reader(nitf_Reader * x) +{ + setNative(x); + getNativeOrThrow(); +} + +Reader::Reader() throw (nitf::NITFException) +{ + setNative(nitf_Reader_construct(&error)); + getNativeOrThrow(); + setManaged(false); +} + +Reader::~Reader() +{ +} + +nitf::Version Reader::getNITFVersion(const std::string& fileName) +{ + return nitf_Reader_getNITFVersion(fileName.c_str()); +} + +nitf::Record Reader::read(nitf::IOHandle & io) throw (nitf::NITFException) +{ + return readIO(io); +} + +nitf::Record Reader::readIO(nitf::IOInterface & io) throw (nitf::NITFException) +{ + //free up the existing record, if we have one + nitf_Reader *reader = getNativeOrThrow(); + if (reader->record) + { + nitf::Record rec(reader->record); + rec.setManaged(false); + } + if (reader->input && !reader->ownInput) + { + nitf::IOInterface oldIO(reader->input); + oldIO.setManaged(false); + } + + nitf_Record * x = nitf_Reader_readIO(getNativeOrThrow(), io.getNative(), + &error); + + // It's possible readIO() failed but actually took ownership of the + // io object. So we need to call setManaged() on it regardless of if the + // function succeeded. + if (getNativeOrThrow()->input == io.getNative()) + { + io.setManaged(true); + } + + if (!x) + throw nitf::NITFException(&error); + nitf::Record rec(x); + + return rec; +} + +nitf::ImageReader Reader::newImageReader(int imageSegmentNumber) + throw (nitf::NITFException) +{ + nitf_ImageReader * x = nitf_Reader_newImageReader(getNativeOrThrow(), + imageSegmentNumber, + NULL, &error); + if (!x) + throw nitf::NITFException(&error); + + nitf::ImageReader reader(x); + //set it so it is NOT managed by the underlying library + //this means the reader is subject to deletion when refcount == 0 + reader.setManaged(false); + return reader; +} + +nitf::ImageReader Reader::newImageReader(int imageSegmentNumber, + const std::map& options) + throw (nitf::NITFException) +{ + nitf::HashTable userOptions; + nrt_HashTable* userOptionsNative = NULL; + + if (!options.empty()) + { + userOptions.setPolicy(NRT_DATA_RETAIN_OWNER); + for (std::map::const_iterator iter = + options.begin(); + iter != options.end(); + ++iter) + { + userOptions.insert(iter->first, iter->second); + } + userOptionsNative = userOptions.getNative(); + } + + nitf_ImageReader* x = nitf_Reader_newImageReader(getNativeOrThrow(), + imageSegmentNumber, + userOptionsNative, + &error); + if (!x) + { + throw nitf::NITFException(&error); + } + + nitf::ImageReader reader(x); + //set it so it is NOT managed by the underlying library + //this means the reader is subject to deletion when refcount == 0 + reader.setManaged(false); + return reader; +} + +nitf::SegmentReader Reader::newDEReader(int deSegmentNumber) + throw (nitf::NITFException) +{ + nitf_SegmentReader * x = nitf_Reader_newDEReader(getNativeOrThrow(), + deSegmentNumber, &error); + if (!x) + throw nitf::NITFException(&error); + nitf::SegmentReader reader(x); + //set it so it is NOT managed by the underlying library + //this means the reader is subject to deletion when refcount == 0 + reader.setManaged(false); + return reader; +} + +nitf::SegmentReader Reader::newGraphicReader(int segmentNumber) + throw (nitf::NITFException) +{ + nitf_SegmentReader * x = + nitf_Reader_newGraphicReader(getNativeOrThrow(), segmentNumber, + &error); + if (!x) + throw nitf::NITFException(&error); + nitf::SegmentReader reader(x); + //set it so it is NOT managed by the underlying library + //this means the reader is subject to deletion when refcount == 0 + reader.setManaged(false); + return reader; +} + +nitf::SegmentReader Reader::newTextReader(int segmentNumber) + throw (nitf::NITFException) +{ + nitf_SegmentReader * x = nitf_Reader_newTextReader(getNativeOrThrow(), + segmentNumber, &error); + if (!x) + throw nitf::NITFException(&error); + nitf::SegmentReader reader(x); + //set it so it is NOT managed by the underlying library + //this means the reader is subject to deletion when refcount == 0 + reader.setManaged(false); + return reader; +} + +nitf::List Reader::getWarningList() const +{ + return nitf::List(getNativeOrThrow()->warningList); +} + +nitf::Record Reader::getRecord() const +{ + return nitf::Record(getNativeOrThrow()->record); +} + +nitf::IOInterface Reader::getInput() const +{ + return nitf::IOInterface(getNativeOrThrow()->input); +} diff --git a/modules/c++/nitf/source/Record.cpp b/modules/c++/nitf/source/Record.cpp new file mode 100644 index 000000000..e708b85d4 --- /dev/null +++ b/modules/c++/nitf/source/Record.cpp @@ -0,0 +1,293 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/Record.hpp" + +using namespace nitf; + +Record::Record(const Record & x) +{ + setNative(x.getNative()); +} + +Record & Record::operator=(const Record & x) +{ + if (&x != this) + setNative(x.getNative()); + return *this; +} + +Record::Record(nitf_Record * x) +{ + setNative(x); + getNativeOrThrow(); +} + +Record::Record(nitf::Version version) throw(nitf::NITFException) +{ + setNative(nitf_Record_construct(version, &error)); + getNativeOrThrow(); + setManaged(false); +} + +nitf::Record Record::clone() throw(nitf::NITFException) +{ + nitf::Record dolly(nitf_Record_clone(getNativeOrThrow(), &error)); + dolly.setManaged(false); + return dolly; +} + +Record::~Record(){} + +nitf::Version Record::getVersion() +{ + return nitf_Record_getVersion(getNativeOrThrow()); +} + +nitf::FileHeader Record::getHeader() +{ + return nitf::FileHeader(getNativeOrThrow()->header); +} + +void Record::setHeader(nitf::FileHeader & value) +{ + //release the one currently "owned" + nitf::FileHeader fh = nitf::FileHeader(getNativeOrThrow()->header); + fh.setManaged(false); + + //have the library manage the "new" one + getNativeOrThrow()->header = value.getNative(); + value.setManaged(true); +} + +nitf::Uint32 Record::getNumImages() +{ + nitf::Uint32 num = nitf_Record_getNumImages(getNativeOrThrow(), &error); + + if (NITF_INVALID_NUM_SEGMENTS( num )) + throw nitf::NITFException(&error); + + return num; +} + +nitf::Uint32 Record::getNumGraphics() +{ + + nitf::Uint32 num = nitf_Record_getNumGraphics(getNativeOrThrow(), &error); + + if (NITF_INVALID_NUM_SEGMENTS( num )) + throw nitf::NITFException(&error); + + return num; +} + +nitf::Uint32 Record::getNumLabels() +{ + + nitf::Uint32 num = nitf_Record_getNumLabels(getNativeOrThrow(), &error); + + if (NITF_INVALID_NUM_SEGMENTS( num )) + throw nitf::NITFException(&error); + + return num; +} + +nitf::Uint32 Record::getNumTexts() +{ + nitf::Uint32 num = nitf_Record_getNumTexts(getNativeOrThrow(), &error); + + if (NITF_INVALID_NUM_SEGMENTS( num )) + throw nitf::NITFException(&error); + + return num; +} + +nitf::Uint32 Record::getNumDataExtensions() +{ + nitf::Uint32 num = nitf_Record_getNumDataExtensions(getNativeOrThrow(), + &error); + + if (NITF_INVALID_NUM_SEGMENTS( num )) + throw nitf::NITFException(&error); + + return num; +} + +nitf::Uint32 Record::getNumReservedExtensions() +{ + nitf::Uint32 num = nitf_Record_getNumReservedExtensions(getNativeOrThrow(), + &error); + + if (NITF_INVALID_NUM_SEGMENTS( num )) + throw nitf::NITFException(&error); + + return num; +} + + +nitf::List Record::getImages() +{ + return nitf::List(getNativeOrThrow()->images); +} + +nitf::List Record::getGraphics() +{ + return nitf::List(getNativeOrThrow()->graphics); +} + +nitf::List Record::getLabels() +{ + return nitf::List(getNativeOrThrow()->labels); +} + +nitf::List Record::getTexts() +{ + return nitf::List(getNativeOrThrow()->texts); +} + +nitf::List Record::getDataExtensions() +{ + return nitf::List(getNativeOrThrow()->dataExtensions); +} + +nitf::List Record::getReservedExtensions() +{ + return nitf::List(getNativeOrThrow()->reservedExtensions); +} + +nitf::ImageSegment Record::newImageSegment(int index) +{ + nitf_ImageSegment* x = nitf_Record_newImageSegment(getNativeOrThrow(), &error); + if (!x) + throw nitf::NITFException(&error); + if (index >= 0) //move it, if we need to + moveImageSegment(getImages().getSize() - 1, index); + return nitf::ImageSegment(x); +} + +nitf::GraphicSegment Record::newGraphicSegment(int index) +{ + nitf_GraphicSegment* x = nitf_Record_newGraphicSegment(getNativeOrThrow(), &error); + if (!x) + throw nitf::NITFException(&error); + if (index >= 0) //move it, if we need to + moveGraphicSegment(getGraphics().getSize() - 1, index); + return nitf::GraphicSegment(x); +} + +nitf::TextSegment Record::newTextSegment(int index) +{ + nitf_TextSegment* x = nitf_Record_newTextSegment(getNativeOrThrow(), &error); + if (!x) + throw nitf::NITFException(&error); + if (index >= 0) //move it, if we need to + moveTextSegment(getTexts().getSize() - 1, index); + return nitf::TextSegment(x); +} + +nitf::DESegment Record::newDataExtensionSegment(int index) +{ + nitf_DESegment* x = nitf_Record_newDataExtensionSegment(getNativeOrThrow(), &error); + if (!x) + throw nitf::NITFException(&error); + if (index >= 0) //move it, if we need to + moveDataExtensionSegment(getDataExtensions().getSize() - 1, index); + return nitf::DESegment(x); +} + +void Record::removeImageSegment(nitf::Uint32 segmentNumber) +{ + if (NITF_SUCCESS != nitf_Record_removeImageSegment(getNativeOrThrow(), segmentNumber, &error)) + throw nitf::NITFException(&error); +} + +void Record::removeGraphicSegment(nitf::Uint32 segmentNumber) +{ + if (NITF_SUCCESS != nitf_Record_removeGraphicSegment(getNativeOrThrow(), segmentNumber, &error)) + throw nitf::NITFException(&error); +} + +void Record::removeTextSegment(nitf::Uint32 segmentNumber) +{ + if (NITF_SUCCESS != nitf_Record_removeTextSegment(getNativeOrThrow(), segmentNumber, &error)) + throw nitf::NITFException(&error); +} + +void Record::removeLabelSegment(nitf::Uint32 segmentNumber) +{ + if (NITF_SUCCESS != nitf_Record_removeLabelSegment(getNativeOrThrow(), segmentNumber, &error)) + throw nitf::NITFException(&error); +} + +void Record::removeDataExtensionSegment(nitf::Uint32 segmentNumber) +{ + if (NITF_SUCCESS != nitf_Record_removeDataExtensionSegment(getNativeOrThrow(), segmentNumber, &error)) + throw nitf::NITFException(&error); +} + +void Record::removeReservedExtensionSegment(nitf::Uint32 segmentNumber) +{ + if (NITF_SUCCESS != nitf_Record_removeReservedExtensionSegment(getNativeOrThrow(), segmentNumber, &error)) + throw nitf::NITFException(&error); +} + +void Record::moveImageSegment(nitf::Uint32 oldIndex, int newIndex) +{ + if (NITF_SUCCESS != nitf_Record_moveImageSegment(getNativeOrThrow(), + oldIndex, newIndex, &error)) + throw nitf::NITFException(&error); +} + +void Record::moveTextSegment(nitf::Uint32 oldIndex, int newIndex) +{ + if (NITF_SUCCESS != nitf_Record_moveTextSegment(getNativeOrThrow(), + oldIndex, newIndex, &error)) + throw nitf::NITFException(&error); +} + +void Record::moveGraphicSegment(nitf::Uint32 oldIndex, int newIndex) +{ + if (NITF_SUCCESS != nitf_Record_moveGraphicSegment(getNativeOrThrow(), + oldIndex, newIndex, &error)) + throw nitf::NITFException(&error); +} + +void Record::moveDataExtensionSegment(nitf::Uint32 oldIndex, int newIndex) +{ + if (NITF_SUCCESS != nitf_Record_moveDataExtensionSegment(getNativeOrThrow(), + oldIndex, newIndex, &error)) + throw nitf::NITFException(&error); +} + +void Record::moveLabelSegment(nitf::Uint32 oldIndex, int newIndex) +{ + if (NITF_SUCCESS != nitf_Record_moveLabelSegment(getNativeOrThrow(), + oldIndex, newIndex, &error)) + throw nitf::NITFException(&error); +} + +void Record::moveReservedExtensionSegment(nitf::Uint32 oldIndex, int newIndex) +{ + if (NITF_SUCCESS != nitf_Record_moveReservedExtensionSegment(getNativeOrThrow(), + oldIndex, newIndex, &error)) + throw nitf::NITFException(&error); +} diff --git a/modules/c++/nitf/source/SegmentReader.cpp b/modules/c++/nitf/source/SegmentReader.cpp new file mode 100644 index 000000000..1092a4978 --- /dev/null +++ b/modules/c++/nitf/source/SegmentReader.cpp @@ -0,0 +1,81 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/SegmentReader.hpp" + +using namespace nitf; + +SegmentReader::SegmentReader(const SegmentReader & x) +{ + setNative(x.getNative()); +} + +SegmentReader & SegmentReader::operator=(const SegmentReader & x) +{ + if (&x != this) + setNative(x.getNative()); + return *this; +} + +SegmentReader::SegmentReader(nitf_SegmentReader * x) +{ + setNative(x); + getNativeOrThrow(); +} + +SegmentReader::~SegmentReader(){} + + +void SegmentReader::read +( + NITF_DATA *buffer, /*!< Buffer to hold data */ + size_t count /*!< Amount of data to return */ +) throw (nitf::NITFException) +{ + if (!nitf_SegmentReader_read(getNativeOrThrow(), buffer, count, &error)) + throw nitf::NITFException(&error); +} + + +nitf::Off SegmentReader::seek +( + nitf::Off offset, /*!< The seek offset */ + int whence /*!< Starting at (SEEK_SET, SEEK_CUR, SEEK_END)*/ +) throw (nitf::NITFException) +{ + offset = nitf_SegmentReader_seek(getNativeOrThrow(), offset, whence, &error); + if (offset < 0) + throw nitf::NITFException(&error); + return offset; +} + + +nitf::Off SegmentReader::tell() +{ + return nitf_SegmentReader_tell(getNativeOrThrow(), &error); +} + + +nitf::Off SegmentReader::getSize() +{ + return nitf_SegmentReader_getSize(getNativeOrThrow(), &error); +} diff --git a/modules/c++/nitf/source/SegmentSource.cpp b/modules/c++/nitf/source/SegmentSource.cpp new file mode 100644 index 000000000..0b91ce0c4 --- /dev/null +++ b/modules/c++/nitf/source/SegmentSource.cpp @@ -0,0 +1,50 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/SegmentSource.hpp" + +nitf::SegmentMemorySource::SegmentMemorySource(const char * data, size_t size, + nitf::Off start, int byteSkip, bool copyData) throw (nitf::NITFException) +{ + setNative(nitf_SegmentMemorySource_construct(data, size, start, byteSkip, + copyData, &error)); + setManaged(false); +} + +nitf::SegmentFileSource::SegmentFileSource(nitf::IOHandle & io, + nitf::Off start, int byteSkip) throw (nitf::NITFException) +{ + setNative(nitf_SegmentFileSource_constructIO(io.getNative(), + start, byteSkip, + &error)); + setManaged(false); + io.setManaged(true); //TODO unmanage on deletion +} + +nitf::SegmentReaderSource::SegmentReaderSource(nitf::SegmentReader reader) + throw (nitf::NITFException) +{ + setNative(nitf_SegmentReaderSource_construct(reader.getNativeOrThrow(), + &error)); + setManaged(false); + reader.setManaged(true); //TODO unmanage on deletion +} diff --git a/modules/c++/nitf/source/SegmentWriter.cpp b/modules/c++/nitf/source/SegmentWriter.cpp new file mode 100644 index 000000000..9ea2006b7 --- /dev/null +++ b/modules/c++/nitf/source/SegmentWriter.cpp @@ -0,0 +1,60 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/SegmentWriter.hpp" + +using namespace nitf; + +SegmentWriter::SegmentWriter() throw (nitf::NITFException) +{ + setNative(nitf_SegmentWriter_construct(&error)); + setManaged(false); +} + +SegmentWriter::SegmentWriter(nitf::SegmentSource segmentSource) + throw (nitf::NITFException) +{ + setNative(nitf_SegmentWriter_construct(&error)); + setManaged(false); + attachSource(segmentSource); +} + +SegmentWriter::~SegmentWriter() +{ +// if (mAdopt && mSegmentSource) +// { +// mSegmentSource->decRef(); +// delete mSegmentSource; +// } +} + +void SegmentWriter::attachSource(nitf::SegmentSource segmentSource) + throw (nitf::NITFException) +{ + if (!nitf_SegmentWriter_attachSource(getNativeOrThrow(), + segmentSource.getNative(), &error)) + throw nitf::NITFException(&error); + segmentSource.setManaged(true); +// segmentSource->incRef(); +// mSegmentSource = segmentSource; +// mAdopt = adopt; +} diff --git a/modules/c++/nitf/source/SubWindow.cpp b/modules/c++/nitf/source/SubWindow.cpp new file mode 100644 index 000000000..9819706bd --- /dev/null +++ b/modules/c++/nitf/source/SubWindow.cpp @@ -0,0 +1,142 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/SubWindow.hpp" + +using namespace nitf; + +SubWindow::SubWindow(const SubWindow & x) +{ + setNative(x.getNative()); +} + +SubWindow & SubWindow::operator=(const SubWindow & x) +{ + if (&x != this) + setNative(x.getNative()); + return *this; +} + +SubWindow::SubWindow(nitf_SubWindow * x) +{ + setNative(x); + getNativeOrThrow(); +} + +SubWindow::SubWindow() throw(nitf::NITFException) : mDownSampler(NULL) +{ + setNative(nitf_SubWindow_construct(&error)); + getNativeOrThrow(); + setManaged(false); +} + +SubWindow::~SubWindow() +{ + if (isValid() && getNative()->downsampler) + { + nitf::DownSampler ds(getNativeOrThrow()->downsampler); + //decrement the current DownSampler + ds.decRef(); + } +} + +nitf::Uint32 SubWindow::getStartRow() const +{ + return getNativeOrThrow()->startRow; +} + +void SubWindow::setStartRow(nitf::Uint32 value) +{ + getNativeOrThrow()->startRow = value; +} + +nitf::Uint32 SubWindow::getNumRows() const +{ + return getNativeOrThrow()->numRows; +} + +void SubWindow::setNumRows(nitf::Uint32 value) +{ + getNativeOrThrow()->numRows = value; +} + +nitf::Uint32 SubWindow::getStartCol() const +{ + return getNativeOrThrow()->startCol; +} + +void SubWindow::setStartCol(nitf::Uint32 value) +{ + getNativeOrThrow()->startCol = value; +} + +nitf::Uint32 SubWindow::getNumCols() const +{ + return getNativeOrThrow()->numCols; +} + +void SubWindow::setNumCols(nitf::Uint32 value) +{ + getNativeOrThrow()->numCols = value; +} + +nitf::Uint32 SubWindow::getBandList(int i) +{ + return getNativeOrThrow()->bandList[i]; +} + +void SubWindow::setBandList(nitf::Uint32 * value) +{ + getNativeOrThrow()->bandList = (nitf_Uint32*)value; +} + +nitf::Uint32 SubWindow::getNumBands() const +{ + return getNativeOrThrow()->numBands; +} + +void SubWindow::setNumBands(nitf::Uint32 value) +{ + getNativeOrThrow()->numBands = value; +} + +void SubWindow::setDownSampler(nitf::DownSampler* downSampler) + throw (nitf::NITFException) +{ + if (getNativeOrThrow()->downsampler) + { + nitf::DownSampler ds(getNativeOrThrow()->downsampler); + //decrement the current DownSampler + ds.decRef(); + } + + //increment the reference for this DownSampler + getNativeOrThrow()->downsampler = downSampler->getNative(); + downSampler->incRef(); + mDownSampler = downSampler; +} + + +nitf::DownSampler* SubWindow::getDownSampler() throw (nitf::NITFException) +{ + return mDownSampler; +} diff --git a/modules/c++/nitf/source/TRE.cpp b/modules/c++/nitf/source/TRE.cpp new file mode 100644 index 000000000..3ec7e1223 --- /dev/null +++ b/modules/c++/nitf/source/TRE.cpp @@ -0,0 +1,164 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include +#include "nitf/TRE.hpp" + +using namespace nitf; + +TRE::TRE(const TRE & x) +{ + setNative(x.getNative()); +} + +TRE & TRE::operator=(const TRE & x) +{ + if (&x != this) + setNative(x.getNative()); + return *this; +} + +TRE::TRE(nitf_TRE * x) +{ + setNative(x); + getNativeOrThrow(); +} + +TRE::TRE(NITF_DATA * x) +{ + setNative((nitf_TRE*)x); + getNativeOrThrow(); +} + +TRE & TRE::operator=(NITF_DATA * x) +{ + setNative((nitf_TRE*)x); + getNativeOrThrow(); + return *this; +} + +TRE::TRE(const char* tag) throw(nitf::NITFException) +{ + setNative(nitf_TRE_construct(tag, NULL, &error)); + getNativeOrThrow(); + setManaged(false); +} + +TRE::TRE(const char* tag, const char* id) throw(nitf::NITFException) +{ + setNative(nitf_TRE_construct(tag, (::strlen(id) > 0) ? id : NULL, &error)); + getNativeOrThrow(); + setManaged(false); +} + +TRE::TRE(const std::string& tag) throw(nitf::NITFException) +{ + setNative(nitf_TRE_construct(tag.c_str(), NULL, &error)); + getNativeOrThrow(); + setManaged(false); +} + +TRE::TRE(const std::string& tag, const std::string& id) + throw(nitf::NITFException) +{ + setNative(nitf_TRE_construct(tag.c_str(), + id.empty() ? NULL : id.c_str(), + &error)); + getNativeOrThrow(); + setManaged(false); +} + +nitf::TRE TRE::clone() throw(nitf::NITFException) +{ + nitf::TRE dolly(nitf_TRE_clone(getNativeOrThrow(), &error)); + dolly.setManaged(false); + return dolly; +} + +TRE::~TRE(){} + +TRE::Iterator TRE::begin() +{ + nitf_TREEnumerator* iter = nitf_TRE_begin(getNativeOrThrow(), &error); + if(!iter) + throw nitf::NITFException(Ctxt("Invalid TRE: " + getTag())); + return TRE::Iterator(iter); +} + +TRE::Iterator TRE::end() throw (nitf::NITFException) +{ + return TRE::Iterator(); +} + +nitf::Field TRE::getField(const std::string& key) + throw(except::NoSuchKeyException) +{ + nitf_Field* field = nitf_TRE_getField(getNativeOrThrow(), key.c_str()); + if (!field) + throw except::NoSuchKeyException(Ctxt(FmtX( + "Field does not exist in TRE: %s", key.c_str()))); + return nitf::Field(field); +} + +nitf::Field TRE::operator[] (const std::string& key) + throw(except::NoSuchKeyException) +{ + return getField(key); +} + +bool TRE::exists(const std::string& key) +{ + return nitf_TRE_exists(getNativeOrThrow(), key.c_str()) == NITF_SUCCESS; +} + +size_t TRE::getCurrentSize() +{ + int size = nitf_TRE_getCurrentSize(getNativeOrThrow(), &error); + if (size < 0) + throw nitf::NITFException(&error); + return (size_t)size; +} + +std::string TRE::getTag() const +{ + return std::string(getNativeOrThrow()->tag); +} + +void TRE::setTag(const std::string & value) +{ + memset(getNativeOrThrow()->tag, 0, 7); + memcpy(getNativeOrThrow()->tag, value.c_str(), 7); +} + +nitf::List TRE::find(const std::string& pattern) +{ + nitf_List* list = nitf_TRE_find(getNative(), pattern.c_str(), &error); + if (!list) + throw except::NoSuchKeyException(); + return nitf::List(list); +} + +std::string TRE::getID() const +{ + const char* id = nitf_TRE_getID(getNativeOrThrow()); + return id ? std::string(id) : ""; +} diff --git a/modules/c++/nitf/source/TextSegment.cpp b/modules/c++/nitf/source/TextSegment.cpp new file mode 100644 index 000000000..a718b2a8d --- /dev/null +++ b/modules/c++/nitf/source/TextSegment.cpp @@ -0,0 +1,109 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/TextSegment.hpp" + +using namespace nitf; + +TextSegment::TextSegment(const TextSegment & x) +{ + setNative(x.getNative()); +} + +TextSegment & TextSegment::operator=(const TextSegment & x) +{ + if (&x != this) + setNative(x.getNative()); + return *this; +} + +TextSegment::TextSegment(nitf_TextSegment * x) +{ + setNative(x); + getNativeOrThrow(); +} + +TextSegment::TextSegment() throw(nitf::NITFException) +{ + setNative(nitf_TextSegment_construct(&error)); + getNativeOrThrow(); + setManaged(false); +} + +TextSegment::TextSegment(NITF_DATA * x) +{ + setNative((nitf_TextSegment*)x); + getNativeOrThrow(); +} + +TextSegment & TextSegment::operator=(NITF_DATA * x) +{ + setNative((nitf_TextSegment*)x); + getNativeOrThrow(); + return *this; +} + +nitf::TextSegment TextSegment::clone() throw(nitf::NITFException) +{ + nitf::TextSegment dolly( + nitf_TextSegment_clone(getNativeOrThrow(), &error)); + dolly.setManaged(false); + return dolly; +} + +TextSegment::~TextSegment(){} + +nitf::TextSubheader TextSegment::getSubheader() +{ + return nitf::TextSubheader(getNativeOrThrow()->subheader); +} + +void TextSegment::setSubheader(nitf::TextSubheader & value) +{ + //release the one currently "owned" + nitf::TextSubheader sub = nitf::TextSubheader(getNativeOrThrow()->subheader); + sub.setManaged(false); + + //have the library manage the "new" one + getNativeOrThrow()->subheader = value.getNative(); + value.setManaged(true); +} + +nitf::Uint64 TextSegment::getOffset() const +{ + return getNativeOrThrow()->offset; +} + +void TextSegment::setOffset(nitf::Uint64 value) +{ + getNativeOrThrow()->offset = value; +} + +nitf::Uint64 TextSegment::getEnd() const +{ + return getNativeOrThrow()->end; +} + +void TextSegment::setEnd(nitf::Uint64 value) +{ + getNativeOrThrow()->end = value; +} diff --git a/modules/c++/nitf/source/TextSubheader.cpp b/modules/c++/nitf/source/TextSubheader.cpp new file mode 100644 index 000000000..d298a7519 --- /dev/null +++ b/modules/c++/nitf/source/TextSubheader.cpp @@ -0,0 +1,145 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/TextSubheader.hpp" + +using namespace nitf; + +TextSubheader::TextSubheader(const TextSubheader & x) +{ + setNative(x.getNative()); +} + +TextSubheader & TextSubheader::operator=(const TextSubheader & x) +{ + if (&x != this) + setNative(x.getNative()); + return *this; +} + +TextSubheader::TextSubheader(nitf_TextSubheader * x) +{ + setNative(x); + getNativeOrThrow(); +} + +TextSubheader::TextSubheader() throw(nitf::NITFException) +{ + setNative(nitf_TextSubheader_construct(&error)); + getNativeOrThrow(); + setManaged(false); +} + +nitf::TextSubheader TextSubheader::clone() throw(nitf::NITFException) +{ + nitf::TextSubheader dolly(nitf_TextSubheader_clone(getNativeOrThrow(), &error)); + dolly.setManaged(false); + return dolly; +} + +TextSubheader::~TextSubheader(){} + +nitf::Field TextSubheader::getFilePartType() +{ + return nitf::Field(getNativeOrThrow()->filePartType); +} + +nitf::Field TextSubheader::getTextID() +{ + return nitf::Field(getNativeOrThrow()->textID); +} + +nitf::Field TextSubheader::getAttachmentLevel() +{ + return nitf::Field(getNativeOrThrow()->attachmentLevel); +} + +nitf::Field TextSubheader::getDateTime() +{ + return nitf::Field(getNativeOrThrow()->dateTime); +} + +nitf::Field TextSubheader::getTitle() +{ + return nitf::Field(getNativeOrThrow()->title); +} + +nitf::Field TextSubheader::getSecurityClass() +{ + return nitf::Field(getNativeOrThrow()->securityClass); +} + +nitf::FileSecurity TextSubheader::getSecurityGroup() +{ + return nitf::FileSecurity(getNativeOrThrow()->securityGroup); +} + +void TextSubheader::setSecurityGroup(nitf::FileSecurity value) +{ + //release the owned security group + nitf::FileSecurity fs = nitf::FileSecurity(getNativeOrThrow()->securityGroup); + fs.setManaged(false); + + //have the library manage the new securitygroup + getNativeOrThrow()->securityGroup = value.getNative(); + value.setManaged(true); +} + +nitf::Field TextSubheader::getEncrypted() +{ + return nitf::Field(getNativeOrThrow()->encrypted); +} + +nitf::Field TextSubheader::getFormat() +{ + return nitf::Field(getNativeOrThrow()->format); +} + +nitf::Field TextSubheader::getExtendedHeaderLength() +{ + return nitf::Field(getNativeOrThrow()->extendedHeaderLength); +} + +nitf::Field TextSubheader::getExtendedHeaderOverflow() +{ + return nitf::Field(getNativeOrThrow()->extendedHeaderOverflow); +} + +nitf::Extensions TextSubheader::getExtendedSection() +{ + return nitf::Extensions(getNativeOrThrow()->extendedSection); +} + +void TextSubheader::setExtendedSection(nitf::Extensions value) +{ + if (getNativeOrThrow()->extendedSection) + { + //release the one currently "owned", if different + nitf::Extensions exts = nitf::Extensions(getNativeOrThrow()->extendedSection); + if (exts != value) + exts.setManaged(false); + } + + //have the library manage the "new" one + getNativeOrThrow()->extendedSection = value.getNative(); + value.setManaged(true); +} diff --git a/modules/c++/nitf/source/Utils.cpp b/modules/c++/nitf/source/Utils.cpp new file mode 100644 index 000000000..ba1e625fc --- /dev/null +++ b/modules/c++/nitf/source/Utils.cpp @@ -0,0 +1,29 @@ +#include "nitf/Utils.hpp" + +using namespace nitf; + +bool Utils::isNumeric(std::string str) +{ + return (bool) nitf_Utils_isNumeric((char*) str.c_str()); +} + +bool Utils::isAlpha(std::string str) +{ + return (bool) nitf_Utils_isNumeric((char*) str.c_str()); +} + +void Utils::decimalToGeographic(double decimal, int* degrees, int* minutes, + double* seconds) +{ + nitf_Utils_decimalToGeographic(decimal, degrees, minutes, seconds); +} + +double Utils::geographicToDecimal(int degrees, int minutes, double seconds) +{ + return nitf_Utils_geographicToDecimal(degrees, minutes, seconds); +} + +char Utils::cornersTypeAsCoordRep(nitf::CornersType type) +{ + return nitf_Utils_cornersTypeAsCoordRep(type); +} diff --git a/modules/c++/nitf/source/WriteHandler.cpp b/modules/c++/nitf/source/WriteHandler.cpp new file mode 100644 index 000000000..820f767af --- /dev/null +++ b/modules/c++/nitf/source/WriteHandler.cpp @@ -0,0 +1,47 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/WriteHandler.hpp" + +void nitf::WriteHandler::write(nitf::IOInterface& handle) + throw (nitf::NITFException) +{ + nitf_WriteHandler *handler = getNativeOrThrow(); + if (handler && handler->iface) + { + if (!handler->iface->write(handler->data, + handle.getNative(), &error)) + throw nitf::NITFException(&error); + } + else + throw except::NullPointerReference(Ctxt("WriteHandler")); +} + +nitf::StreamIOWriteHandler::StreamIOWriteHandler( + nitf::IOInterface& sourceHandle, nitf::Uint64 offset, + nitf::Uint64 bytes) +{ + setNative(nitf_StreamIOWriteHandler_construct( + sourceHandle.getNative(), offset, bytes, &error)); + setManaged(false); +} + diff --git a/modules/c++/nitf/source/Writer.cpp b/modules/c++/nitf/source/Writer.cpp new file mode 100644 index 000000000..8a3437d71 --- /dev/null +++ b/modules/c++/nitf/source/Writer.cpp @@ -0,0 +1,257 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/Writer.hpp" + +using namespace nitf; + +void WriterDestructor::operator()(nitf_Writer *writer) +{ + if (writer && writer->record) + { + // this tells the handle manager that the Record is no longer managed + nitf::Record rec(writer->record); + rec.setManaged(false); + } + if (writer && writer->output) + { + // this tells the handle manager that the IOInterface is no longer managed + nitf::IOInterface io(writer->output); + io.setManaged(false); + } + nitf_Writer_destruct(&writer); +} + +Writer::Writer(const Writer & x) +{ + setNative(x.getNative()); +} + +Writer & Writer::operator=(const Writer & x) +{ + if (&x != this) + setNative(x.getNative()); + return *this; +} + +Writer::Writer(nitf_Writer * x) +{ + setNative(x); + getNativeOrThrow(); +} + +Writer::Writer() throw (nitf::NITFException) +{ + setNative(nitf_Writer_construct(&error)); + getNativeOrThrow(); + setManaged(false); +} + +Writer::~Writer() +{ +// for (std::vector::iterator it = mWriteHandlers.begin(); it +// != mWriteHandlers.end(); ++it) +// { +// delete *it; +// } +} + +void Writer::write() +{ + NITF_BOOL x = nitf_Writer_write(getNativeOrThrow(), &error); + if (!x) + throw nitf::NITFException(&error); +} + +void Writer::prepare(nitf::IOHandle & io, nitf::Record & record) + throw (nitf::NITFException) +{ + prepareIO(io, record); +} + +void Writer::prepareIO(nitf::IOInterface & io, nitf::Record & record) + throw (nitf::NITFException) +{ + NITF_BOOL x = nitf_Writer_prepareIO(getNativeOrThrow(), record.getNative(), + io.getNative(), &error); + + // It's possible prepareIO() failed but actually took ownership of one + // or both of these objects. So we need to call setManaged() on them + // properly regardless of if the function succeeded. + if (getNativeOrThrow()->record == record.getNative()) + { + record.setManaged(true); + } + + if (getNativeOrThrow()->output == io.getNative()) + { + io.setManaged(true); + } + + if (!x) + { + throw nitf::NITFException(&error); + } +} + +void Writer::setImageWriteHandler(int index, + mem::SharedPtr writeHandler) + throw (nitf::NITFException) +{ + if (!nitf_Writer_setImageWriteHandler(getNativeOrThrow(), index, + writeHandler->getNative(), &error)) + throw nitf::NITFException(&error); + writeHandler->setManaged(true); + mWriteHandlers.push_back(writeHandler); +} + +void Writer::setGraphicWriteHandler(int index, + mem::SharedPtr writeHandler) + throw (nitf::NITFException) +{ + if (!nitf_Writer_setGraphicWriteHandler(getNativeOrThrow(), index, + writeHandler->getNative(), &error)) + throw nitf::NITFException(&error); + writeHandler->setManaged(true); + mWriteHandlers.push_back(writeHandler); +} + +void Writer::setTextWriteHandler(int index, + mem::SharedPtr writeHandler) + throw (nitf::NITFException) +{ + if (!nitf_Writer_setTextWriteHandler(getNativeOrThrow(), index, + writeHandler->getNative(), &error)) + throw nitf::NITFException(&error); + writeHandler->setManaged(true); + mWriteHandlers.push_back(writeHandler); +} + +void Writer::setDEWriteHandler(int index, + mem::SharedPtr writeHandler) + throw (nitf::NITFException) +{ + if (!nitf_Writer_setDEWriteHandler(getNativeOrThrow(), index, + writeHandler->getNative(), &error)) + throw nitf::NITFException(&error); + writeHandler->setManaged(true); + mWriteHandlers.push_back(writeHandler); +} + +nitf::ImageWriter Writer::newImageWriter(int imageNumber) + throw (nitf::NITFException) +{ + nitf_SegmentWriter * x = nitf_Writer_newImageWriter(getNativeOrThrow(), + imageNumber, NULL, &error); + if (!x) + throw nitf::NITFException(&error); + + //manage the writer + nitf::ImageWriter writer(x); + writer.setManaged(true); + return writer; +} + +nitf::ImageWriter Writer::newImageWriter(int imageNumber, + const std::map& options) + throw (nitf::NITFException) +{ + nitf::HashTable userOptions; + nrt_HashTable* userOptionsNative = NULL; + + if (!options.empty()) + { + userOptions.setPolicy(NRT_DATA_RETAIN_OWNER); + for (std::map::const_iterator iter = + options.begin(); + iter != options.end(); + ++iter) + { + userOptions.insert(iter->first, iter->second); + } + userOptionsNative = userOptions.getNative(); + } + + nitf_SegmentWriter* x = nitf_Writer_newImageWriter(getNativeOrThrow(), + imageNumber, + userOptionsNative, + &error); + + if (!x) + { + throw nitf::NITFException(&error); + } + + //manage the writer + nitf::ImageWriter writer(x); + writer.setManaged(true); + return writer; +} + +nitf::SegmentWriter Writer::newGraphicWriter(int graphicNumber) + throw (nitf::NITFException) +{ + nitf_SegmentWriter * x = + nitf_Writer_newGraphicWriter(getNativeOrThrow(), graphicNumber, + &error); + if (!x) + throw nitf::NITFException(&error); + + //manage the writer + nitf::SegmentWriter writer(x); + writer.setManaged(true); + return writer; +} + +nitf::SegmentWriter Writer::newTextWriter(int textNumber) + throw (nitf::NITFException) +{ + nitf_SegmentWriter * x = nitf_Writer_newTextWriter(getNativeOrThrow(), + textNumber, &error); + if (!x) + throw nitf::NITFException(&error); + + //manage the writer + nitf::SegmentWriter writer(x); + writer.setManaged(true); + return writer; +} + +nitf::SegmentWriter Writer::newDEWriter(int deNumber) + throw (nitf::NITFException) +{ + nitf_SegmentWriter * x = nitf_Writer_newDEWriter(getNativeOrThrow(), + deNumber, &error); + if (!x) + throw nitf::NITFException(&error); + + //manage the writer + nitf::SegmentWriter writer(x); + writer.setManaged(true); + return writer; +} + +//! Get the warningList +nitf::List Writer::getWarningList() +{ + return nitf::List(getNativeOrThrow()->warningList); +} diff --git a/modules/c++/nitf/tests/Makefile.in b/modules/c++/nitf/tests/Makefile.in new file mode 100644 index 000000000..cb95893ac --- /dev/null +++ b/modules/c++/nitf/tests/Makefile.in @@ -0,0 +1,55 @@ +# ========================================================================= +# This file is part of NITRO +# ========================================================================= +# +# (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems +# +# NITRO is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, If not, +# see . +# + +#---------------------------------------- +# General area +#---------------------------------------- +include ../build/Makefile + +EXE = $(TESTS:.cpp=) +OBJS = ${TESTS:.cpp=.o} +#---------------------------------------- +# Build commands +#---------------------------------------- +all: $(EXE) + +$(EXE): $(OBJS) dirs + $(COMPILE) -o $@ $@.o $(LINK) + mv $@ $(TESTDIR) + +#---------------------------------------- +# Rule for setting up dir. structure +#---------------------------------------- +dirs: + \mkdir -p $(TESTDIR) + + +.SUFFIXES: .o .cpp +.cpp.o: + $(COMPILE) -c $? + +clean: + \rm -f $(OBJS) + \rm -rf $(TESTDIR) + +raw: clean + \rm -f Makefile + diff --git a/modules/c++/nitf/tests/test_blank.ntf b/modules/c++/nitf/tests/test_blank.ntf new file mode 100644 index 000000000..a4b88a318 --- /dev/null +++ b/modules/c++/nitf/tests/test_blank.ntf @@ -0,0 +1 @@ +NITF02.1003BF01123456789020070101000000File title Blank file, file header only ****************************************U121234567890112123456789012345678901212345678123411234567812345678901234567890123456789012345678901231123456789012345678901234567890123456789011234567812345678901234512345123450AAA123456789012345678901234(000) 000-0000****0000000003880003880000000000000000000000000000 diff --git a/modules/c++/nitf/tests/test_buffered_write.cpp b/modules/c++/nitf/tests/test_buffered_write.cpp new file mode 100644 index 000000000..71ea0df83 --- /dev/null +++ b/modules/c++/nitf/tests/test_buffered_write.cpp @@ -0,0 +1,252 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include +#include +#include + +/* + * This test tests the round-trip process of taking an input NITF + * file and writing it to a new file. This includes writing the image + * segments (headers, extensions, and image data). + * + * This example differs from test_writer_3 in that it tests the + * BufferedWriter classes, and writes the entire file as a set of + * configurable sized blocks. The last block may be smaller than the others + * if the data does not fill the block. + * + */ + +nitf::Record doRead(const std::string& inFile); + +std::string makeBandName(const std::string& rootFile, int imageNum, int bandNum) +{ + std::string::size_type pos = rootFile.find_last_of("/\\"); + std::ostringstream os; + os << rootFile.substr(pos + 1) << "__" << imageNum << "_band_" << bandNum; + std::string newFile = os.str(); + + while ((pos = newFile.find(".")) != std::string::npos) + newFile.replace(pos, 1, "_"); + newFile += ".man"; + return newFile; +} + +nitf::ImageSource setupBands(int nbands, int imageNum, const std::string& inRootFile) +{ + nitf::ImageSource iSource; + for (int i = 0; i < nbands; i++) + { + std::string inFile = makeBandName(inRootFile, imageNum, i); + nitf::FileSource fs(inFile, 0, 1, 0); + iSource.addBand(fs); + } + return iSource; +} + +void doWrite(nitf::Record record, + const std::string& inRootFile, + const std::string& outFile, + size_t bufferSize) +{ + std::cout << "Preparing to write file in " << bufferSize + << " size blocks" << std::endl; + + nitf::BufferedWriter output(outFile, bufferSize); + nitf::Writer writer; + writer.prepareIO(output, record); + + int numImages = record.getHeader().getNumImages(); + nitf::ListIterator end = record.getImages().end(); + nitf::ListIterator iter = record.getImages().begin(); + + for (int i = 0; i < numImages && iter != end; ++i, ++iter) + { + nitf::ImageSegment imseg; + imseg = *iter; + int nbands = imseg.getSubheader().getNumImageBands(); + nitf::ImageWriter iWriter = writer.newImageWriter(i); + nitf::ImageSource iSource = setupBands(nbands, i, inRootFile); + iWriter.attachSource(iSource); + } + writer.write(); + //output.close(); + + std::cout << "Write block info: " << std::endl; + std::cout << "------------------------------------" << std::endl; + std::cout << "Total number of blocks written: " << output.getNumBlocksWritten() << std::endl; + std::cout << "Of those, " << output.getNumPartialBlocksWritten() << " were less than buffer size " << bufferSize << std::endl; + + + +} + +int main(int argc, char **argv) +{ + try + { + // Check argv and make sure we are happy + if (argc < 3 || argc > 4) + { + std::cout << "Usage: %s (block-size - default is 8192)\n" << argv[0] << std::endl; + exit(EXIT_FAILURE); + } + + size_t blockSize = 8192; + if (argc == 4) + blockSize = str::toType(argv[3]); + + // Check that wew have a valid NITF + if (nitf::Reader::getNITFVersion(argv[1]) == NITF_VER_UNKNOWN ) + { + std::cout << "Invalid NITF: " << argv[1] << std::endl; + exit(EXIT_FAILURE); + } + + nitf::Record record = doRead(argv[1]); + doWrite(record, argv[1], argv[2], blockSize); + return 0; + } + catch (except::Throwable & t) + { + std::cout << t.getMessage() << std::endl; + } +} + + +void manuallyWriteImageBands(nitf::ImageSegment & segment, + const std::string& imageName, + nitf::ImageReader& deserializer, + int imageNumber) +{ + int padded; + + nitf::ImageSubheader subheader = segment.getSubheader(); + + + nitf::Uint32 nBits = subheader.getNumBitsPerPixel(); + nitf::Uint32 nBands = subheader.getNumImageBands(); + nitf::Uint32 xBands = subheader.getNumMultispectralImageBands(); + nBands += xBands; + + nitf::Uint32 nRows = subheader.getNumRows(); + nitf::Uint32 nColumns = subheader.getNumCols(); + + //one row at a time + size_t subWindowSize = nColumns * NITF_NBPP_TO_BYTES(nBits); + + std::cout << "NBANDS -> " << nBands << std::endl + << "XBANDS -> " << xBands << std::endl + << "NROWS -> " << nRows << std::endl + << "NCOLS -> " << nColumns << std::endl + << "PVTYPE -> " << subheader.getPixelValueType().toString() << std::endl + << "NBPP -> " << subheader.getNumBitsPerPixel().toString() << std::endl + << "ABPP -> " << subheader.getActualBitsPerPixel().toString() << std::endl + << "PJUST -> " << subheader.getPixelJustification().toString() << std::endl + << "IMODE -> " << subheader.getImageMode().toString() << std::endl + << "NBPR -> " << subheader.getNumBlocksPerRow().toString() << std::endl + << "NBPC -> " << subheader.getNumBlocksPerCol().toString() << std::endl + << "NPPBH -> " << (int)subheader.getNumPixelsPerHorizBlock() << std::endl + << "NPPBV -> " << (int)subheader.getNumPixelsPerVertBlock() << std::endl + << "IC -> " << subheader.getImageCompression().toString() << std::endl + << "COMRAT -> " << subheader.getCompressionRate().toString() << std::endl; + + nitf::Uint8** buffer = new nitf::Uint8*[nBands]; + nitf::Uint32* bandList = new nitf::Uint32[nBands]; + + for (nitf::Uint32 band = 0; band < nBands; band++) + bandList[band] = band; + + nitf::SubWindow subWindow; + subWindow.setStartCol(0); + subWindow.setNumRows(1); + subWindow.setNumCols(nColumns); + + // necessary ? + nitf::DownSampler* pixelSkip = new nitf::PixelSkip(1, 1); + subWindow.setDownSampler(pixelSkip); + subWindow.setBandList(bandList); + subWindow.setNumBands(nBands); + + assert(buffer); + for (nitf::Uint32 i = 0; i < nBands; i++) + { + buffer[i] = new nitf::Uint8[subWindowSize]; + assert(buffer[i]); + } + + std::vector handles; + //make the files + for (nitf::Uint32 i = 0; i < nBands; i++) + { + std::string name = makeBandName(imageName, imageNumber, i); + nitf::IOHandle toFile(name, NITF_ACCESS_WRITEONLY, NITF_CREATE); + handles.push_back(toFile); + } + + //read all row blocks and write to disk + for (nitf::Uint32 i = 0; i < nRows; ++i) + { + subWindow.setStartRow(i); + deserializer.read(subWindow, buffer, &padded); + for (nitf::Uint32 j = 0; j < nBands; j++) + { + handles[j].write((const char*)buffer[j], subWindowSize); + } + } + + //close output handles + for (nitf::Uint32 i = 0; i < nBands; i++) + handles[i].close(); + + /* free buffers */ + for (nitf::Uint32 i = 0; i < nBands; i++) + delete [] buffer[i]; + delete [] buffer; + delete [] bandList; + delete pixelSkip; +} + + +nitf::Record doRead(const std::string& inFile) +{ + nitf::Reader reader; + nitf::IOHandle io(inFile); + nitf::Record record = reader.read(io); + + /* Set this to the end, so we'll know when we're done! */ + nitf::ListIterator end = record.getImages().end(); + nitf::ListIterator iter = record.getImages().begin(); + for (int count = 0, numImages = record.getHeader().getNumImages(); + count < numImages && iter != end; ++count, ++iter) + { + nitf::ImageSegment imageSegment = *iter; + nitf::ImageReader deserializer = reader.newImageReader(count); + std::cout << "Writing image " << count << "..." << std::endl; + + /* Write the thing out */ + manuallyWriteImageBands(imageSegment, inFile, deserializer, count); + std::cout << "done.\n" << std::endl; + } + + return record; +} diff --git a/modules/c++/nitf/tests/test_create++.cpp b/modules/c++/nitf/tests/test_create++.cpp new file mode 100644 index 000000000..3c5922c1f --- /dev/null +++ b/modules/c++/nitf/tests/test_create++.cpp @@ -0,0 +1,48 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + +int main(int argc, char** argv) +{ + try + { + if (argc != 2) + { + throw nitf::NITFException(Ctxt(FmtX("Usage %s \n", + argv[0]))); + } + + nitf::IOHandle handle(argv[1], NITF_ACCESS_READONLY, NITF_CREATE); + if (handle.isValid()) + { + throw nitf::NITFException(Ctxt("Test failed!")); + } + printf("Create succeeded. Check file permissions to make sure they're OK\n"); + handle.close(); + return 0; + } + catch (except::Throwable& t) + { + std::cout << t.getTrace() << std::endl; + } +} diff --git a/modules/c++/nitf/tests/test_date.cpp b/modules/c++/nitf/tests/test_date.cpp new file mode 100644 index 000000000..628f61353 --- /dev/null +++ b/modules/c++/nitf/tests/test_date.cpp @@ -0,0 +1,67 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + + +#define MAX_DATE_STRING 1024 + +int main(int argc, char** argv) +{ + try + { + char dateBuf[MAX_DATE_STRING]; + nitf::DateTime now; + + std::cout << "Year: " << now.getYear() << std::endl; + std::cout << "Month: " << now.getMonth() << std::endl; + std::cout << "Day Of Month: " << now.getDayOfMonth() << std::endl; + std::cout << "Day Of Week: " << now.getDayOfWeek() << std::endl; + std::cout << "Day Of Year: " << now.getDayOfYear() << std::endl; + std::cout << "Hour: " << now.getHour() << std::endl; + std::cout << "Minute: " << now.getMinute() << std::endl; + std::cout << "Second: " << now.getSecond() << std::endl; + std::cout << "Millis: " << now.getTimeInMillis() << std::endl; + + now.format(NITF_DATE_FORMAT_21, dateBuf, NITF_FDT_SZ + 1); + std::cout << "The Current NITF 2.1 Formatted Date: " << dateBuf << std::endl; + +#ifndef WIN32 + nitf::DateTime dolly(dateBuf, NITF_DATE_FORMAT_21); + std::cout << "Roundtripped: " << dolly.getTimeInMillis() << std::endl; +#endif + + now.format(NITF_DATE_FORMAT_20, dateBuf, NITF_FDT_SZ + 1); + std::cout << "The Current NITF 2.0 Formatted Date: " << dateBuf << std::endl; + +#ifndef WIN32 + dolly = nitf::DateTime(dateBuf, NITF_DATE_FORMAT_20); + std::cout << "Roundtripped: " << dolly.getTimeInMillis() << std::endl; +#endif + + exit(EXIT_SUCCESS); + } + catch (except::Throwable & t) + { + std::cout << t.getTrace() << std::endl; + } +} diff --git a/modules/c++/nitf/tests/test_date_set.cpp b/modules/c++/nitf/tests/test_date_set.cpp new file mode 100644 index 000000000..0c8f918af --- /dev/null +++ b/modules/c++/nitf/tests/test_date_set.cpp @@ -0,0 +1,69 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + + +#define MAX_DATE_STRING 1024 + +int main(int argc, char** argv) +{ + try + { + char dateBuf[MAX_DATE_STRING]; + nitf::DateTime now; + + now.setYear(2009); + + std::cout << "Year: " << now.getYear() << std::endl; + std::cout << "Month: " << now.getMonth() << std::endl; + std::cout << "Day Of Month: " << now.getDayOfMonth() << std::endl; + std::cout << "Day Of Week: " << now.getDayOfWeek() << std::endl; + std::cout << "Day Of Year: " << now.getDayOfYear() << std::endl; + std::cout << "Hour: " << now.getHour() << std::endl; + std::cout << "Minute: " << now.getMinute() << std::endl; + std::cout << "Second: " << now.getSecond() << std::endl; + std::cout << "Millis: " << now.getTimeInMillis() << std::endl; + + now.format(NITF_DATE_FORMAT_21, dateBuf, NITF_FDT_SZ + 1); + std::cout << "The Current NITF 2.1 Formatted Date: " << dateBuf << std::endl; + +#ifndef WIN32 + nitf::DateTime dolly(dateBuf, NITF_DATE_FORMAT_21); + std::cout << "Roundtripped: " << dolly.getTimeInMillis() << std::endl; +#endif + + now.format(NITF_DATE_FORMAT_20, dateBuf, NITF_FDT_SZ + 1); + std::cout << "The Current NITF 2.0 Formatted Date: " << dateBuf << std::endl; + +#ifndef WIN32 + dolly = nitf::DateTime(dateBuf, NITF_DATE_FORMAT_20); + std::cout << "Roundtripped: " << dolly.getTimeInMillis() << std::endl; +#endif + + exit(EXIT_SUCCESS); + } + catch (except::Throwable & t) + { + std::cout << t.getTrace() << std::endl; + } +} diff --git a/modules/c++/nitf/tests/test_des_create++.cpp b/modules/c++/nitf/tests/test_des_create++.cpp new file mode 100644 index 000000000..7a5299a07 --- /dev/null +++ b/modules/c++/nitf/tests/test_des_create++.cpp @@ -0,0 +1,113 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + + +#include + +#include + +/* + Test program for reading a DE segment + + This program creates a NITF file with a file header and a single DE Segment. + + The record is cloned from an input NITF with a single DE segment. Some + fields and the data are modified and the result written out as a new NITF + + The input NITF file should have no DES segments + + This program uses the test_DES_example DE segment + + The calling sequence is: + + test_des_write inputFile outputFile +*/ + +static const char data[] = "123456789ABCDEF0"; + +/* +* Ugly function to create the DES user header (a TRE) +* +* This is here because the C++ library does not seem to have +* a way to do this +*/ + +int main(int argc, char *argv[]) +{ + try + { + if (argc != 3) + { + fprintf(stderr, "Usage %s inputFile outputFile\n", argv[0]); + exit(EXIT_FAILURE); + } + + /* Get the input record */ + + nitf::IOHandle in(argv[1]); /* Input I/O handle */ + nitf::Reader reader; + nitf::Record record = reader.read(in); + + // Create the DE segment + + nitf::DESegment des = record.newDataExtensionSegment(); + + // Set-up DE header + + + des.getSubheader().getFilePartType().set("DE"); + des.getSubheader().getTypeID().set("TEST_DES"); + des.getSubheader().getVersion().set("01"); + des.getSubheader().getSecurityClass().set("U"); + + /* nitf::FileSecurity security = + record.getHeader().getSecurityGroup(); + des.getSubheader().setSecurityGroup(security); */ + nitf::FileSecurity security = + record.getHeader().getSecurityGroup(); + des.getSubheader().setSecurityGroup(security.clone()); + + // Set-up user header + + nitf::TRE *usrHdr = new nitf::TRE("TEST DES", "TEST DES"); + usrHdr->getField("TEST_DES_COUNT").set("16"); + usrHdr->getField("TEST_DES_START").set("065"); + usrHdr->getField("TEST_DES_INCREMENT").set("01"); + + des.getSubheader().setSubheaderFields(*usrHdr); + + nitf::Writer writer; + nitf::IOHandle output_io(argv[2], NITF_ACCESS_WRITEONLY, NITF_CREATE); + writer.prepare(output_io, record); + + nitf::SegmentWriter sWriter = writer.newDEWriter(0); + nitf::SegmentMemorySource sSource(data, strlen(data), 0, 0, false); + sWriter.attachSource(sSource); + writer.write(); + + exit(EXIT_SUCCESS); + } + catch (except::Throwable & t) + { + std::cout << t.getTrace() << std::endl; + } +} diff --git a/modules/c++/nitf/tests/test_direct_block_round_trip.cpp b/modules/c++/nitf/tests/test_direct_block_round_trip.cpp new file mode 100644 index 000000000..72ac6e410 --- /dev/null +++ b/modules/c++/nitf/tests/test_direct_block_round_trip.cpp @@ -0,0 +1,150 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2013, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include +#include +#include +#include +#include +#include + +class TestDirectBlockSource: public nitf::DirectBlockSource +{ +public: + TestDirectBlockSource(nitf::ImageReader& imageReader, + nitf::Uint32 numBands) + throw (nitf::NITFException) : nitf::DirectBlockSource(imageReader, numBands){} + +protected: + virtual void nextBlock(char* buf, + nitf::Uint8* block, + nitf::Uint32 blockNumber, + nitf::Uint64 blockSize) throw (nitf::NITFException) + { + std::cout << "BLOCK NUMBER: " << blockNumber << " " << blockSize << std::endl; + if(buf) + memcpy(buf, block, blockSize); + } +}; + +/* + * This test tests the round-trip process of taking an input NITF + * file and writing it to a new file. This includes writing the image + * segments (headers, extensions, and image data). This is an example + * of how users can write the image data to their NITF file + */ + +int main(int argc, char **argv) +{ + try + { + // Check argv and make sure we are happy + if (argc != 3) + { + std::cout << "Usage: %s \n" << argv[0] + << std::endl; + exit( EXIT_FAILURE); + } + + // Check that wew have a valid NITF + if (nitf::Reader::getNITFVersion(argv[1]) == NITF_VER_UNKNOWN) + { + std::cout << "Invalid NITF: " << argv[1] << std::endl; + exit( EXIT_FAILURE); + } + + //read it in + nitf::Reader reader; + nitf::IOHandle io(argv[1]); + nitf::Record record = reader.read(io); + + //now, let's create the writer + nitf::Writer writer; + nitf::IOHandle output(argv[2], NITF_ACCESS_WRITEONLY, NITF_CREATE); + writer.prepare(output, record); + + nitf::ListIterator iter = record.getImages().begin(); + nitf::Uint32 num = record.getNumImages(); + + std::vector imageReaders; + std::vector imageWriters; + std::map writerOptions; + std::vector > bandSources; + + //nitf::Uint32 numRes = 1; + //writerOptions[C8_NUM_RESOLUTIONS_KEY] = &numRes; + + for (nitf::Uint32 i = 0; i < num; i++) + { + //for the images, we'll use a DirectBlockSource for streaming + nitf::ImageSegment imseg = *iter; + iter++; + imageReaders.push_back(reader.newImageReader(i)); + imageWriters.push_back(writer.newImageWriter(i, writerOptions)); + nitf::ImageSource iSource; + + bandSources.push_back(mem::SharedPtr( + new TestDirectBlockSource(imageReaders[i], 1))); + iSource.addBand(*bandSources[bandSources.size()-1]); + + imageWriters[i].attachSource(iSource); + imageWriters[i].setDirectBlockWrite(1); + } + + num = record.getNumGraphics(); + for (nitf::Uint32 i = 0; i < num; i++) + { + nitf::SegmentReaderSource readerSource(reader.newGraphicReader(i)); + mem::SharedPtr< ::nitf::WriteHandler> segmentWriter( + new nitf::SegmentWriter(readerSource)); + writer.setGraphicWriteHandler(i, segmentWriter); + } + + num = record.getNumTexts(); + for (nitf::Uint32 i = 0; i < num; i++) + { + nitf::SegmentReaderSource readerSource(reader.newTextReader(i)); + mem::SharedPtr< ::nitf::WriteHandler> segmentWriter( + new nitf::SegmentWriter(readerSource)); + writer.setTextWriteHandler(i, segmentWriter); + } + + num = record.getNumDataExtensions(); + for (nitf::Uint32 i = 0; i < num; i++) + { + nitf::SegmentReaderSource readerSource(reader.newDEReader(i)); + mem::SharedPtr< ::nitf::WriteHandler> segmentWriter( + new nitf::SegmentWriter(readerSource)); + writer.setDEWriteHandler(i, segmentWriter); + } + + writer.write(); + output.close(); + io.close(); + return 0; + } + catch (except::Throwable & t) + { + std::cout << "ERROR!: " << t.toString() << std::endl; + } +} + diff --git a/modules/c++/nitf/tests/test_fh.cpp b/modules/c++/nitf/tests/test_fh.cpp new file mode 100644 index 000000000..b4bd9d9a0 --- /dev/null +++ b/modules/c++/nitf/tests/test_fh.cpp @@ -0,0 +1,101 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include +#include +#include + +int main(int argc, char** argv) +{ + try + { + std::cout << "Crazy FileHeader test" << std::endl; + //Sticking a second in breaks the paradigm!!! + nitf::FileHeader fileHeader; + std::cout << "Created FileHeader" << std::endl; + + //fileHeader.name = "1"; + nitf::FileHeader two = fileHeader; + std::cout << "Copied FileHeader" << std::endl; + //two.name = "2"; + + nitf::FileHeader three = two; + std::cout << "Copied FileHeader copy" << std::endl; + //three.name = "3"; + + nitf::FileHeader alone; + std::cout << "Created another FileHeader" << std::endl; + //alone.name = "4"; + + // This guy should be different + nitf::FileHeader myFileHeader; + std::cout << "Created yet another FileHeader" << std::endl; + //myFileHeader.name = "5"; + + nitf::FileHeader myFileCopy = myFileHeader; + std::cout << "Copied yet another FileHeader" << std::endl; + //myFileCopy.name = "6"; + + nitf::FileHeader* myNewCopy = new nitf::FileHeader(myFileCopy); + std::cout << "New-allocated copy of FileHeader" << std::endl; + //myNewCopy->name = "7"; + delete myNewCopy; + std::cout << "Deleted new-allocated copy of FileHeader" << std::endl; + + nitf::FileHeader* myNonCopy = new nitf::FileHeader; + std::cout << "New-allocated a FileHeader" << std::endl; + //myNonCopy->name = "8"; + delete myNonCopy; + std::cout << "Deleted new-allocated FileHeader" << std::endl; + + std::cout << "Setting file header" << std::endl; + fileHeader.getFileHeader().set("NITF"); + std::cout << "Setting file version" << std::endl; + fileHeader.getFileVersion().set("2.1"); + + two = fileHeader; + + std::cout << "Setting file header" << std::endl; + myFileHeader.getFileHeader().set("FTIN"); + std::cout << "Setting file version" << std::endl; + myFileHeader.getFileVersion().set("1.2"); + + nitf::Extensions ext; + + nitf::HashTable hash; + ext.setHash(hash); + + std::cout << fileHeader.getFileHeader().toString() << std::endl; + std::cout << fileHeader.getFileVersion().toString() << std::endl; + std::cout << two.getFileHeader().toString() << std::endl; + std::cout << two.getFileVersion().toString() << std::endl; + + std::cout << myFileHeader.getFileHeader().toString() << std::endl; + std::cout << myFileHeader.getFileVersion().toString() << std::endl; + + return 0; + } + catch (except::Throwable& t) + { + std::cout << t.getTrace() << std::endl; + } +} diff --git a/modules/c++/nitf/tests/test_fhdr_clone++.cpp b/modules/c++/nitf/tests/test_fhdr_clone++.cpp new file mode 100644 index 000000000..c0e62990c --- /dev/null +++ b/modules/c++/nitf/tests/test_fhdr_clone++.cpp @@ -0,0 +1,141 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + +#define SHOW(X) std::cout << #X << "=" << X << std::endl +#define SHOWI(X) std::cout << #X << "=" << X << std::endl +#define PRINT_HDR(X) std::cout << #X; printHdr(X) + +void printHdr(nitf::FileHeader header) +{ + nitf::Uint32 i; + SHOW( header.getFileHeader().toString() ); + SHOW( header.getFileVersion().toString() ); + SHOW( header.getComplianceLevel().toString() ); + SHOW( header.getSystemType().toString() ); + SHOW( header.getOriginStationID().toString() ); + SHOW( header.getFileDateTime().toString() ); + SHOW( header.getFileTitle().toString() ); + SHOW( header.getClassification().toString() ); + SHOW( header.getMessageCopyNum().toString() ); + SHOW( header.getMessageNumCopies().toString() ); + SHOW( header.getEncrypted().toString() ); + SHOW( header.getBackgroundColor().toString() ); + SHOW( header.getOriginatorName().toString() ); + SHOW( header.getOriginatorPhone().toString() ); + SHOWI( (nitf::Uint32)header.getFileLength() ); + SHOWI( (nitf::Uint32)header.getHeaderLength() ); + + printf("The number of IMAGES contained in this file [%d]\n", + (int)header.getNumImages()); + + for (i = 0; i < (nitf::Uint32)header.getNumImages(); i++) + { + printf("\tThe length of IMAGE subheader [%d]: %d bytes\n", + i, (nitf::Uint32)header.getImageInfo(i).getLengthSubheader()); + printf("\tThe length of the IMAGE data: %d bytes\n", + (nitf::Uint32)header.getImageInfo(i).getLengthData()); + } + + printf("The number of GRAPHICS contained in this file [%d]\n", + (nitf::Uint32)header.getNumGraphics()); + + for (i = 0; i < (nitf::Uint32)header.getNumGraphics(); i++) + { + printf("\tThe length of GRAPHICS subheader [%d]: %d bytes\n", + i, (nitf::Uint32)header.getGraphicInfo(i).getLengthSubheader()); + printf("\tThe length of the GRAPHICS data: %d bytes\n\n", + (nitf::Uint32)header.getGraphicInfo(i).getLengthData()); + } + printf("The number of LABELS contained in this file [%d]\n", + (nitf::Uint32)header.getNumLabels()); + + assert((nitf::Uint32)header.getNumLabels() == 0); + + printf("The number of TEXTS contained in this file [%d]\n", + (nitf::Uint32)header.getNumTexts()); + + for (i = 0; i < (nitf::Uint32)header.getNumTexts(); i++) + { + printf("\tThe length of TEXT subheader [%d]: %d bytes\n", + i, (int)header.getTextInfo(i).getLengthSubheader()); + printf("\tThe length of the TEXT data: %d bytes\n\n", + (int)header.getTextInfo(i).getLengthData()); + } + printf("The number of DATA EXTENSIONS contained in this file [%d]\n", + (nitf::Uint32)header.getNumDataExtensions()); + + for (i = 0; i < (nitf::Uint32)header.getNumDataExtensions(); i++) + { + printf("\tThe length of DATA EXTENSION subheader [%d]: %d bytes\n", + i, (nitf::Uint32)header.getDataExtensionInfo(i).getLengthSubheader()); + printf("\tThe length of the DATA EXTENSION data: %d bytes\n\n", + (nitf::Uint32)header.getDataExtensionInfo(i).getLengthData()); + + } + printf("The number of RESERVED EXTENSIONS contained in this file [%d]\n", + (nitf::Uint32)header.getNumReservedExtensions()); + + for (i = 0; i < (nitf::Uint32)header.getNumReservedExtensions(); i++) + { + printf("\tThe length of RESERVED EXTENSION subheader [%d]: %d bytes\n", + i, (nitf::Uint32)header.getReservedExtensionInfo(i).getLengthSubheader()); + printf("\tThe length of the RESERVED EXTENSION data: %d bytes\n\n", + (nitf::Uint32)header.getReservedExtensionInfo(i).getLengthData()); + + } + + printf("The user-defined header length [%d]\n", (nitf::Uint32)header.getUserDefinedHeaderLength()); + + printf("The extended header length [%d]\n", (nitf::Uint32)header.getExtendedHeaderLength()); + +} + + +int main(int argc, char** argv) +{ + try + { + if (argc != 2) + { + throw nitf::NITFException(Ctxt(FmtX("Usage: %s \n", argv[0]))); + } + + nitf::Reader reader; + nitf::IOHandle io(argv[1]); + + /* Ironically, the one function you would think */ + /* needs a boolean return value returns void */ + nitf::Record header = reader.read(io); + nitf::Record twin = header.clone(); + + PRINT_HDR( header.getHeader() ); + PRINT_HDR( twin.getHeader() ); + + return 0; + } + catch (except::Throwable& t) + { + std::cout << t.getTrace() << std::endl; + } +} diff --git a/modules/c++/nitf/tests/test_file_source++.cpp b/modules/c++/nitf/tests/test_file_source++.cpp new file mode 100644 index 000000000..c72538706 --- /dev/null +++ b/modules/c++/nitf/tests/test_file_source++.cpp @@ -0,0 +1,112 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include +#include + +#include + +namespace +{ +static const char* const MEMBUF = "ABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABC"; +static const size_t MEMSIZE = strlen(MEMBUF); +static const size_t NUM_BANDS = 3; +static const char* const FILENAME = "test_file.src"; + +void printBand(const char* band, const char* s, size_t size) +{ + std::cout << "Band " << s << ": ["; + for (size_t i = 0; i < size; ++i) + { + std::cout << band[i]; + } + std::cout << "]\n"; +} + + +std::string prepareIO() +{ + /* First we'll create the file for them... */ + nitf::IOHandle handle(FILENAME, NITF_ACCESS_WRITEONLY, NITF_CREATE); + + /* And we'll write our buffer out */ + handle.write(MEMBUF, MEMSIZE); + handle.close(); + + return std::string(FILENAME); +} +} + +int main(int argc, char **argv) +{ + const int bandSize = MEMSIZE / NUM_BANDS; + const std::string fname = prepareIO(); + + const int numBytesPerPix = 1; + + /* Construct the band sources */ + nitf::FileSource bs0(fname, 0, numBytesPerPix, NUM_BANDS - 1); + nitf::FileSource bs1(fname, 1, numBytesPerPix, NUM_BANDS - 1); + nitf::FileSource bs2(fname, 2, numBytesPerPix, NUM_BANDS - 1); + nitf::FileSource all(fname, 0, numBytesPerPix, 0); + + /* Construct in memory band buffers -- for testing -- 0 terminate strings */ + std::vector band0Vec(bandSize + 1); + char* const band0 = &band0Vec[0]; + + std::vector band1Vec(bandSize + 1); + char* const band1 = &band1Vec[0]; + + std::vector band2Vec(bandSize + 1); + char* const band2 = &band2Vec[0]; + + std::vector allBandsVec(MEMSIZE + 1); + char* const allBands = &allBandsVec[0]; + + band0[bandSize] = band1[bandSize] = band2[bandSize] = allBands[MEMSIZE] = + '\0'; + + /* Read half of the info for one band. This makes sure that we */ + /* are capable of picking up where we left off */ + bs0.read(band0, (MEMSIZE / NUM_BANDS / 2)); + bs1.read(band1, (MEMSIZE / NUM_BANDS / 2)); + bs2.read(band2, (MEMSIZE / NUM_BANDS / 2)); + + /* Pick up where we left off and keep going */ + bs0.read(&band0[MEMSIZE / NUM_BANDS / 2], (MEMSIZE / NUM_BANDS / 2)); + bs1.read(&band1[MEMSIZE / NUM_BANDS / 2], (MEMSIZE / NUM_BANDS / 2)); + bs2.read(&band2[MEMSIZE / NUM_BANDS / 2], (MEMSIZE / NUM_BANDS / 2)); + all.read(allBands, MEMSIZE); + + /* Now we would like to verify the results of our reading */ + + /* The first three bands should be all of the same letter B1=A, B2=B, B3=C*/ + printBand(band0, "1", MEMSIZE / NUM_BANDS); + printBand(band1, "2", MEMSIZE / NUM_BANDS); + printBand(band2, "3", MEMSIZE / NUM_BANDS); + + /* The last band source was applied to the entire buffer, so it should */ + /* look the same as the original memory source */ + printBand(allBands, "ALL", MEMSIZE); + + return 0; +} diff --git a/modules/c++/nitf/tests/test_functional.cpp b/modules/c++/nitf/tests/test_functional.cpp new file mode 100644 index 000000000..1581e98e9 --- /dev/null +++ b/modules/c++/nitf/tests/test_functional.cpp @@ -0,0 +1,73 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include +#include +#include +#include +#include + +#include "test_functional.h" + +int main(int argc, char **argv) +{ + try + { + nitf::Reader reader; + if ( argc != 2 ) + throw nitf::NITFException(Ctxt(FmtX("Usage: %s \n", argv[0]))); + + nitf::IOHandle io(argv[1]); + nitf::Record record = reader.read(io); + nitf::FileHeader fileHeader = record.getHeader(); + + FieldAdapterMap map; //create the adapter map + map.insert("fileHeader", std::mem_fun_ref(&nitf::FileHeader::getFileHeader)); + map.insert("fileDateTime", std::mem_fun_ref(&nitf::FileHeader::getFileDateTime)); + map.insert("fileVersion", std::mem_fun_ref(&nitf::FileHeader::getFileVersion)); + + //we can loop over them in order + for(FieldAdapterMap::Iterator it = map.begin(); it != map.end(); ++it) + std::cout << it->first << ": [" << it->second(fileHeader).toString() << "]" << std::endl; + + map.remove("fileHeader"); + //loop again + for(FieldAdapterMap::Iterator it = map.begin(); it != map.end(); ++it) + std::cout << it->first << ": [" << it->second(fileHeader).toString() << "]" << std::endl; + + FieldAdapterMap securityMap; + securityMap.insert("classificationSystem", std::mem_fun_ref(&nitf::FileSecurity::getClassificationSystem)); + securityMap.insert("codewords", std::mem_fun_ref(&nitf::FileSecurity::getCodewords)); + + //we can query them by name + nitf::FileSecurity security = fileHeader.getSecurityGroup(); + std::cout << "[" << securityMap["classificationSystem"](security).toString() << "]" << std::endl; + std::cout << "[" << securityMap["codewords"](security).toString() << "]" << std::endl; + + io.close(); + return 0; + } + catch (except::Throwable& t) + { + std::cout << "ERROR: " << t.getTrace() << std::endl; + } +} diff --git a/modules/c++/nitf/tests/test_functional.h b/modules/c++/nitf/tests/test_functional.h new file mode 100644 index 000000000..0189a58c3 --- /dev/null +++ b/modules/c++/nitf/tests/test_functional.h @@ -0,0 +1,90 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_TEST_FUNCTIONAL_H__ +#define __NITF_TEST_FUNCTIONAL_H__ + +#include +#include +#include +#include +#include + +template +class FieldAdapterMap +{ +private: + std::map > mMap; + std::vector< std::pair< std::string, + std::mem_fun_ref_t > > mVec; + +public: +typedef typename std::vector< std::pair< std::string, + std::mem_fun_ref_t > >::iterator Iterator; + + FieldAdapterMap() {} + virtual ~FieldAdapterMap() {} + + Iterator begin() { return mVec.begin(); } + Iterator end() { return mVec.end(); } + + std::mem_fun_ref_t operator[] (const std::string& key) + throw(except::NoSuchKeyException) + { + if (!exists(key)) + throw except::NoSuchKeyException(key); + return mMap.find(key)->second; + } + + bool exists(const std::string& key) + { + return mMap.find(key) != mMap.end(); + } + + void insert(const std::string& key, std::mem_fun_ref_t func) + { + mMap.insert(std::pair >(key, func)); + mVec.push_back(std::pair >(key, func)); + } + + void remove(const std::string& key) + { + if (exists(key)) + { + mMap.erase(mMap.find(key)); + for (Iterator it = begin(); it != end(); ++it) + { + if (it->first == key) + { + mVec.erase(it); + break; + } + } + } + } + +}; + + +#endif diff --git a/modules/c++/nitf/tests/test_handles.cpp b/modules/c++/nitf/tests/test_handles.cpp new file mode 100644 index 000000000..e06956268 --- /dev/null +++ b/modules/c++/nitf/tests/test_handles.cpp @@ -0,0 +1,205 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include +#include +#include +#include "nitf/HandleManager.hpp" +#include "nitf/Field.hpp" +#include "nitf/BandInfo.hpp" +#include "nitf/SubWindow.hpp" +#include "nitf/List.hpp" +#include "nitf/FileHeader.hpp" +#include "nitf/HashTable.hpp" +#include "nitf/Extensions.hpp" +#include "nitf/TRE.hpp" +#include "nitf/ImageSegment.hpp" +#include "nitf/ImageSubheader.hpp" +#include "nitf/TextSegment.hpp" +#include "nitf/GraphicSegment.hpp" +#include "nitf/LabelSegment.hpp" +#include "nitf/DESegment.hpp" +#include "nitf/RESegment.hpp" +#include "nitf/Reader.hpp" +#include "nitf/Writer.hpp" +#include "nitf/PluginRegistry.hpp" +#include +#include + +template +class Foo +{ +protected: + virtual void bar() {std::cout << "HERE1" << std::endl;} +public: + Foo(){} + virtual ~Foo(){bar();} +}; + + +template +class Bar : public Foo +{ +protected: + virtual void bar() { std::cout << "HERE2" << std::endl; } +public: + Bar(){} + ~Bar(){bar();} +}; + + +int main(int argc, char** argv) +{ + try + { + nitf_Error e; + +// Foo* foo = new Bar(); +// delete foo; + + nitf_Field* cField = nitf_Field_construct(100, NITF_BCS_N, &e); + nitf::Field field(cField); + + { + nitf::Field field2(cField); + } + + std::cout << field.isValid() << std::endl; + + + nitf_BandInfo* cBandInfo = nitf_BandInfo_construct(&e); + assert(cBandInfo); + + nitf::BandInfo info(cBandInfo); + + std::cout << (int)info.getNumLUTs() << std::endl; + + std::cout << "HERE!!!!!!!!!!!!!!!!!!!!" << std::endl; + nitf::SubWindow sub; + nitf::SubWindow sub2 = sub; + sub.setNumRows(5); + + nitf::PixelSkip p(1, 1); + sub.setDownSampler(p); + sub.setDownSampler(p); + sub.setDownSampler(p); + sub.setDownSampler(p); + + nitf::PixelSkip p2(1, 1); + sub.setDownSampler(p2); + sub.setDownSampler(p); + + + nitf_SubWindow* subw = nitf_SubWindow_construct(&e); + nitf::SubWindow sub3(subw); + std::cout << sub.getNumRows() << " == " << sub2.getNumRows() << std::endl; + + + nitf::List list; + nitf::List list2 = list; + + { + nitf::FileHeader header; + nitf::FileHeader header2(header.clone()); + //should be not equal + std::cout << "Equal? " << (header == header2) << std::endl; + nitf::FileHeader header3(header2); + //these two should be equal + std::cout << "Equal? " << (header3 == header2) << std::endl; + } + + nitf::HashTable hash; + + nitf::Extensions extensions; + { + nitf::ImageSegment imageSeg; + nitf::ImageSubheader imageSub; + + imageSeg.getSubheader().getImageId() = "Test Image"; + std::cout << imageSeg.getSubheader().getImageId().toString() << std::endl; + nitf::Field f = imageSeg.getSubheader().getImageId(); + std::cout << f.toString() << std::endl; + + nitf::ImageSegment imageSeg2 = imageSeg.clone(); + nitf::ImageSubheader imageSub2(imageSub.clone()); + + extensions = imageSub.getExtendedSection(); + } + + nitf::TextSegment tSeg; + nitf::TextSubheader tSub; + + nitf::GraphicSegment gSeg; + nitf::GraphicSubheader gSub; + + nitf::DESegment dSeg; + nitf::DESubheader dSub; + + nitf::LabelSegment rSeg; + nitf::LabelSubheader rSub; + + nitf::TRE tre("JITCID"); + //tre.print(); + std::cout << "HERE!!!!!" << std::endl; + + nitf::Reader reader; + nitf::Writer writer; + + + //open a file + sys::OS os; + std::vector< std::string > files; + for (int i = 1; i < argc; ++i) + { + if (!os.exists(argv[i])) + std::cout << "Error -> File does not exist: " << argv[i] << std::endl; + else + files.push_back(argv[i]); + } + + for (std::vector< std::string >::iterator it = files.begin(); it != files.end(); ++it) + { + nitf::IOHandle handle(*it); + nitf::Reader rdr; + nitf::Record rec = rdr.read(handle); + + std::cout << "CODEWORDS: " << rec.getHeader().getSecurityGroup().getCodewords().toString() << std::endl; + rec.getHeader().getSecurityGroup().getCodewords() = "TEST"; + std::cout << "CODEWORDS: " << rec.getHeader().getSecurityGroup().getCodewords().toString() << std::endl; + nitf::FileSecurity security; + rec.getHeader().setSecurityGroup(security); + std::cout << "CODEWORDS: " << rec.getHeader().getSecurityGroup().getCodewords().toString() << std::endl; + std::cout << "Num Images: " << rec.getImages().getSize() << std::endl; + } + + nitf_SubWindow_destruct(&subw); + nitf_Field_destruct(&cField); + nitf_BandInfo_destruct(&cBandInfo); + } + catch(except::Exception& ex) + { + std::cerr << "ERROR: " << ex.getMessage() << std::endl; + return 1; + } + + return 0; +} diff --git a/modules/c++/nitf/tests/test_hash_table_1++.cpp b/modules/c++/nitf/tests/test_hash_table_1++.cpp new file mode 100644 index 000000000..c4a70b854 --- /dev/null +++ b/modules/c++/nitf/tests/test_hash_table_1++.cpp @@ -0,0 +1,158 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include +#include + +/* For this first test case, the DATA is a simple char* */ +/* This case should be trivial since a data pointer is */ +/* always the same size in C */ + +int main(int argc, char **argv) +{ + try + { + /* The hash table configurator */ + std::ifstream config; + + /* The search file -- look for this text */ + std::ifstream search; + + /* A key buffer */ + std::string keyBuf(""); + + nitf::HashTable hashTable(4); + + /* We didnt allocate the valueBuf -- its static */ + /* As a result, we need to notify our hash table NOT to */ + /* destroy it on failure */ + hashTable.setPolicy(NITF_DATA_RETAIN_OWNER); + + /* Make sure our key value file and search file exist */ + if (argc != 3) + { + throw nitf:: + NITFException(Ctxt + (FmtX + ("Usage: %s \n", + argv[0]))); + } + /* Open our config file, this contains the key-value pairs we */ + /* will insert into our hash, in the order key[tab]value */ + config.open(argv[1]); + + if (!config.good()) + { + /* If we didnt open, freak out at the user */ + throw nitf:: + NITFException(Ctxt + (FmtX + ("Could not find file [%s]\n", argv[1]))); + } + + std::vector < char *>values; + /* Scan the configuration file, and read into the buffers */ + while (config.good()) + { + /* A value buffer */ + values.push_back(new char[512]); + + config >> keyBuf >> values[values.size() - 1]; + + if (keyBuf.length() > 0) + { + + printf("Read Key: %s = %s\n", keyBuf.c_str(), + values[values.size() - 1]); + + /* Now comes the important part -- insert */ + hashTable.insert(keyBuf, values[values.size() - 1]); + } + + /* Be nice -- reset buffers */ + keyBuf = ""; + } + /* Close the configurator */ + config.close(); + + /* Now, lets be expansive and print the list */ + hashTable.print(); + + /* Open the search file -- this contains keys to search for */ + search.open(argv[2]); + + /* If we couldnt open */ + if (!search.good()) + { + /* Die a sad death */ + throw nitf:: + NITFException(Ctxt + (FmtX + ("Could not find file [%s]\n", argv[1]))); + } + /* Reset the key again, we need it one more time */ + keyBuf = ""; + while (search.good()) + { + search >> keyBuf; + + printf("Searching for key [%s] in hash table\n", + keyBuf.c_str()); + + if (keyBuf.length() > 0) + { + + try + { + /* Find the key/value pair */ + nitf::Pair where = hashTable.find(keyBuf); + + /* Its there in the hash!! */ + + printf("\t[%s] Located the value! Value: [%s]\n", + keyBuf.c_str(), (char *) where.getData()); + } + catch (except::NoSuchKeyException & t) + { + printf("\t[%s] Search unsuccessful [%s]. No such key\n", + keyBuf.c_str(), + t.getMessage().c_str()); + } + } + + /* Reset the key buffer */ + keyBuf = ""; + + } + /* Close the search file */ + search.close(); + + for (unsigned int i = 0; i < values.size(); i++) + delete[]values[i]; + + return 0; + } + catch (except::Throwable & t) + { + std::cout << t.getMessage() << std::endl; + } +} diff --git a/modules/c++/nitf/tests/test_image_loading++.cpp b/modules/c++/nitf/tests/test_image_loading++.cpp new file mode 100644 index 000000000..9d82953c1 --- /dev/null +++ b/modules/c++/nitf/tests/test_image_loading++.cpp @@ -0,0 +1,225 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include +#include + +void writeImage(nitf::ImageSegment &segment, + nitf::Reader &reader, + const int imageNumber, + const char *imageName, + nitf_Uint32 rowSkipFactor, + nitf_Uint32 columnSkipFactor, bool optz) +{ + size_t subWindowSize; + nitf::SubWindow subWindow; + unsigned int i; + int padded; + nitf::Uint8** buffer = NULL; + nitf::Uint32 band; + nitf::Uint32 * bandList; + + nitf::ImageReader deserializer = reader.newImageReader(imageNumber); + + // missing skip factor + nitf::ImageSubheader subheader = segment.getSubheader(); + + nitf::Uint32 nBits = subheader.getNumBitsPerPixel(); + + nitf::Uint32 nBands = subheader.getNumImageBands(); + nitf::Uint32 xBands = subheader.getNumMultispectralImageBands(); + nBands += xBands; + + + nitf::Uint32 nRows = subheader.getNumRows(); + nitf::Uint32 nCols = subheader.getNumCols(); + subWindowSize = (size_t)(nRows / rowSkipFactor) * + (size_t)(nCols / columnSkipFactor) * + (size_t)NITF_NBPP_TO_BYTES(nBits); + + if (optz) + { + std::string irep = + segment.getSubheader().getImageRepresentation().toString(); + std::string ic = + segment.getSubheader().getImageCompression().toString(); + + if (nBands == 3 && segment.getSubheader().getImageMode().toString() + == "P" && str::startsWith(irep, "RGB") + && NITF_NBPP_TO_BYTES(nBits) == 1 && str::startsWith(ic, "N")) + { + subWindowSize *= nBands; + nBands = 1; + std::cout << "Using accelerated 3-band RGB mode pix-interleaved image" << std::endl; + } + if (nBands == 2 && segment.getSubheader().getImageMode().toString() + == "P" && str::startsWith(ic, "N")) + { + + subWindowSize *= nBands; + nBands = 1; + std::cout << "Using accelerated 2-band IQ mode pix-interleaved image" << std::endl; + } + } + + + std::cout << "NBANDS -> " << nBands << std::endl; + std::cout << "XBANDS -> " << xBands << std::endl; + std::cout << "NROWS -> " << nRows << std::endl; + std::cout << "NCOLS -> " << nCols << std::endl; + std::cout << "PVTYPE -> " << subheader.getPixelValueType().toString() << std::endl; + std::cout << "NBPP -> " << subheader.getNumBitsPerPixel() .toString() << std::endl; + std::cout << "ABPP -> " << subheader.getActualBitsPerPixel().toString() << std::endl; + std::cout << "PJUST -> " << subheader.getPixelJustification().toString() << std::endl; + std::cout << "IMODE -> " << subheader.getImageMode().toString() << std::endl; + std::cout << "NBPR -> " << subheader.getNumBlocksPerRow().toString() << std::endl; + std::cout << "NBPC -> " << subheader.getNumBlocksPerCol().toString() << std::endl; + std::cout << "NPPBH -> " << (int)subheader.getNumPixelsPerHorizBlock() << std::endl; + std::cout << "NPPBV -> " << (int)subheader.getNumPixelsPerVertBlock() << std::endl; + std::cout << "IC -> " << subheader.getImageCompression().toString() << std::endl; + std::cout << "COMRAT -> " << subheader.getCompressionRate().toString() << std::endl; + + std::cout << "Allocating work buffer..." << std::endl; + + buffer = new nitf::Uint8*[nBands]; + assert(buffer); + + band = 0; + bandList = new nitf::Uint32[nBands]; + + subWindow.setStartCol(0); + subWindow.setStartRow(0); + + subWindow.setNumRows(nRows / rowSkipFactor); + subWindow.setNumCols(nCols / columnSkipFactor); + + nitf::PixelSkip pixelSkip(rowSkipFactor, columnSkipFactor); + + subWindow.setDownSampler(&pixelSkip); + + for (band = 0; band < nBands; band++) + { + bandList[band] = band; + buffer[band] = new nitf::Uint8[subWindowSize]; + assert(buffer[band]); + } + subWindow.setBandList(bandList); + subWindow.setNumBands(nBands); + + std::cout << "Reading image..." << std::endl; + deserializer.read(subWindow, buffer, &padded); + + std::cout << "Call completed!" << std::endl; + + std::cout << "Writing bands..." << std::endl; + for (i = 0; i < nBands; i++) + { + std::cout << "Writing band # " << i << std::endl; + std::string base = sys::Path::basename(imageName); + + size_t where = 0; + while ((where = base.find(".")) != (size_t)std::string::npos) + base.replace(where, 1, "_"); + + std::ostringstream file; + file << base << "__" << imageNumber << "__" + << nRows / rowSkipFactor << '_' + << nCols / columnSkipFactor << '_' + << nBits << "_band_" << i << ".out"; + + nitf::IOHandle toFile(file.str(), NITF_ACCESS_WRITEONLY, NITF_CREATE); + toFile.write((const char *) buffer[i], subWindowSize); + toFile.close(); + std::cout << "Finished # " << i << std::endl; + } + + for (band = 0; band < nBands; band++) + delete [] buffer[band]; + delete [] buffer; + delete [] bandList; +} + + +int main(int argc, char **argv) +{ + /* Skip factors */ + nitf_Uint32 rowSkipFactor = 1; + nitf_Uint32 columnSkipFactor = 1; + + try + { + /* If you didnt give us a nitf file, we're croaking */ + if (argc < 2) + { + std::cout << "Usage: " << argv[0] << " [-o]" + << std::endl; + exit(EXIT_FAILURE); + } + + bool optz = (argc > 2 && std::string(argv[2]) == "-o"); + + /* This is the reader */ + nitf::Reader reader; + + /* This is the io handle we will give the reader to parse */ + nitf::IOHandle io(argv[1]); + + /* Read the file (first pass) */ + nitf::Record record = reader.read(io); + /* These iterators are for going through the image segments */ + nitf::ListIterator iter; + nitf::ListIterator end; + + /* And set this one to the end, so we'll know when we're done! */ + iter = record.getImages().begin(); + end = record.getImages().end(); + std::cout << "Iterating list of images..." << std::endl; + /* While we are not done... */ + for (int count = 0; iter != end; ++iter, ++count) + { + std::cout << "Getting image segment..." << std::endl; + nitf::ImageSegment imageSegment((nitf_ImageSegment *) iter.get()); + + std::cout << "Retrieved." << std::endl; + std::cout << "Writing image... " << std::endl; + + /* Write the thing out */ + writeImage(imageSegment, reader, count, argv[1], + rowSkipFactor, columnSkipFactor, optz); + std::cout << "done." << std::endl; + } + } + catch (except::Exception &thr) + { + std::cout << "Caught module exception: " << thr.toString() << std::endl; + } + catch (std::exception & ex) + { + std::cout << "Caught C++ exception: " << ex.what() << std::endl; + } + catch (...) + { + std::cout << "Caught unknown exception" << std::endl; + } + + return 0; +} diff --git a/modules/c++/nitf/tests/test_io.cpp b/modules/c++/nitf/tests/test_io.cpp new file mode 100644 index 000000000..c8f4392a9 --- /dev/null +++ b/modules/c++/nitf/tests/test_io.cpp @@ -0,0 +1,49 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include +#include +#include + +int main(int argc, char** argv) +{ + try + { + nitf::MemoryIO memIO(1024); + std::string val = "NITF"; + memIO.write(val.c_str(), 4); + std::cout << "tell: " << memIO.tell() << std::endl; + + memIO.seek(0, NITF_SEEK_SET); + char buf[5]; + memIO.read(buf, 4); + buf[4] = 0; + + std::cout << "val: " << buf << std::endl; + memIO.close(); + return 0; + } + catch (except::Throwable& t) + { + std::cout << t.getTrace() << std::endl; + } +} diff --git a/modules/c++/nitf/tests/test_list_1.cpp b/modules/c++/nitf/tests/test_list_1.cpp new file mode 100644 index 000000000..8d21b4ff1 --- /dev/null +++ b/modules/c++/nitf/tests/test_list_1.cpp @@ -0,0 +1,86 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + +int main(int argc, char **argv) +{ + try + { + /* Iterator to a list */ + nitf::ListIterator it; + + /* Iterator to the end of list */ + nitf::ListIterator endList; + + /* Integer for iteration */ + int i; + + /* Construct a new list */ + nitf::List l; + + /* Put in */ + for (i = 0; i < argc; i++) + { + /* Push the data back */ + l.pushBack((NITF_DATA*)argv[i]); + + } + /* Recall */ + it = l.begin(); + + /* End of list pointer */ + endList = l.end(); + + /* While we are not at the end */ + while ( it != endList) + { + /* Get the last data */ + char* p = (char*)it.get(); + /* Make sure */ + assert(p != NULL); + + /* Show the data */ + printf("Found data: [%s]\n", p); + + /* Increment the list iterator */ + it++; + } + + /* Set the list to the beginning */ + it = l.begin(); + + /* Pop the front off, until the list is empty */ + while ( !l.isEmpty() ) + { + char* p = (char*)l.popFront(); + printf("Popping data value [%s]\n", p); + } + + /* Double check */ + //assert( l.getHandle() == NULL ); + } + catch (except::Throwable& t) + { + std::cout << t.getTrace() << std::endl; + } +} diff --git a/modules/c++/nitf/tests/test_list_2.cpp b/modules/c++/nitf/tests/test_list_2.cpp new file mode 100644 index 000000000..44ba297b3 --- /dev/null +++ b/modules/c++/nitf/tests/test_list_2.cpp @@ -0,0 +1,92 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + +int main(int argc, char **argv) +{ + try + { + /* Iterator to a list */ + nitf::ListIterator it; + + /* Iterator to the end of list */ + nitf::ListIterator endList; + + /* Integer for iteration */ + int i; + + /* Construct a new list */ + nitf::List l; + + /* Put in */ + for (i = 0; i < argc; i++) + { + /* Push the data back */ + l.pushBack((NITF_DATA*)argv[i]); + + } + /* Recall */ + it = l.begin(); + + /* End of list pointer */ + endList = l.end(); + + /* While we are not at the end */ + while ( it != endList) + { + /* Get the last data */ + char* p = (char*)it.get(); + /* Make sure */ + assert(p != NULL); + + /* Show the data */ + printf("Found data: [%s]\n", p); + + /* Increment the list iterator */ + it++; + } + + /* Set the list to the beginning */ + it = l.begin(); + + /* While we are not at the end */ + while ( it != endList) + { + /* Get the last data */ + char* p = (char*)l.remove(it); + /* Make sure */ + assert(p != NULL); + + /* Show the data */ + printf("Removed data: [%s]\n", p); + + } + + /* Double check */ + //assert( l.getHandle() == NULL ); + } + catch (except::Throwable& t) + { + std::cout << t.getTrace() << std::endl; + } +} diff --git a/modules/c++/nitf/tests/test_mem_source.cpp b/modules/c++/nitf/tests/test_mem_source.cpp new file mode 100644 index 000000000..ef3c68b50 --- /dev/null +++ b/modules/c++/nitf/tests/test_mem_source.cpp @@ -0,0 +1,109 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + + +#include + +const char* MEMBUF "ABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABC"; +#define MEMSIZE strlen(MEMBUF) +#define NUM_BANDS 3 + +void print_band(char* band, const char* s, int size) +{ + int i; + printf("Band %s: [", s); + for (i = 0; i < size; i++) + { + printf("%c", band[i]); + } + printf("]\n"); +} + + +int main(int argc, char **argv) +{ + try + { + int bandSize = MEMSIZE / NUM_BANDS; + + int numBytesPerPix = 1; + + /* Construct the band sources */ + nitf::BandSource* bs0 = + new nitf::MemorySource(MEMBUF, MEMSIZE, 0, numBytesPerPix, NUM_BANDS - 1); + nitf::BandSource* bs1 = + new nitf::MemorySource(MEMBUF, MEMSIZE, 1, numBytesPerPix, NUM_BANDS - 1); + nitf::BandSource* bs2 = + new nitf::MemorySource(MEMBUF, MEMSIZE, 2, numBytesPerPix, NUM_BANDS - 1); + nitf::BandSource* all = + new nitf::MemorySource(MEMBUF, MEMSIZE, 0, numBytesPerPix, 0); + + /* Construct in memory band buffers for testing -- 0 terminate strings */ + char *band_0 = (char*)NITF_MALLOC(bandSize + 1); + char *band_1 = (char*)NITF_MALLOC(bandSize + 1); + char *band_2 = (char*)NITF_MALLOC(bandSize + 1); + char *all_bands = (char*)NITF_MALLOC( MEMSIZE + 1); + band_0[bandSize] = 0; + band_1[bandSize] = 1; + band_2[bandSize] = 2; + all_bands[ MEMSIZE ] = 0; + + /* Read half of the info for one band. This makes sure that we */ + /* are capable of picking up where we left off */ + bs0->read(band_0, (MEMSIZE / NUM_BANDS / 2)); + bs1->read(band_1, (MEMSIZE / NUM_BANDS / 2)); + bs2->read(band_2, (MEMSIZE / NUM_BANDS / 2)); + + /* Pick up where we left off and keep going */ + bs0->read(&band_0[MEMSIZE / NUM_BANDS / 2], + (MEMSIZE / NUM_BANDS / 2)); + bs1->read(&band_1[MEMSIZE / NUM_BANDS / 2], + (MEMSIZE / NUM_BANDS / 2)); + bs2->read(&band_2[MEMSIZE / NUM_BANDS / 2], + (MEMSIZE / NUM_BANDS / 2)); + all->read(all_bands, MEMSIZE); + + /* Now we would like to verify the results of our reading */ + + /* The first three bands should be all of the same letter B1=A, B2=B, B3=C*/ + print_band(band_0, "1", MEMSIZE / NUM_BANDS); + print_band(band_1, "2", MEMSIZE / NUM_BANDS); + print_band(band_2, "3", MEMSIZE / NUM_BANDS); + + /* The last band source was applied to the entire buffer, so it should */ + /* look the same as the original memory source */ + print_band(all_bands, "ALL", MEMSIZE); + + NITF_FREE(band_0); + NITF_FREE(band_1); + NITF_FREE(band_2); + NITF_FREE(all_bands); + delete bs0; + delete bs1; + delete bs2; + return 0; + } + catch (except::Throwable & t) + { + std::cout << t.getMessage() << std::endl; + } +} diff --git a/modules/c++/nitf/tests/test_mt_record.cpp b/modules/c++/nitf/tests/test_mt_record.cpp new file mode 100644 index 000000000..4d00db192 --- /dev/null +++ b/modules/c++/nitf/tests/test_mt_record.cpp @@ -0,0 +1,77 @@ +#include +#include + + +class RecordThread : public sys::Thread +{ +public: + RecordThread() {} + virtual ~RecordThread() {} + //static sys::Mutex m; + + virtual void run() + { + nitf::Record record(NITF_VER_21); + nitf::Writer writer; + nitf::FileHeader header = record.getHeader(); + header.getFileHeader().set("NITF"); + header.getComplianceLevel().set("09"); + header.getSystemType().set("BF01"); + header.getOriginStationID().set("Bckyd"); + header.getFileTitle().set("FTITLE"); + header.getClassification().set("U"); + header.getMessageCopyNum().set("00000"); + header.getMessageNumCopies().set("00000"); + header.getEncrypted().set("0"); + header.getBackgroundColor().setRawData((char*)"000", 3); + header.getOriginatorName().set(""); + header.getOriginatorPhone().set(""); + const std::string name = "ACFTB"; + //m.lock(); + nitf::TRE* acftb = new nitf::TRE(name, name); + + std::string file = str::toString(sys::getThreadID()) + ".ntf"; + + nitf::IOHandle output(file, NITF_ACCESS_WRITEONLY, NITF_CREATE); + writer.prepare(output, record); + + writer.write(); + } + +}; + + +//sys::Mutex RecordThread::m; + +const int NTHR = 2; +int main(int argc, char** argv) +{ + try + { + sys::Thread** thrs = new sys::Thread*[NTHR]; + + for (unsigned int i = 0; i < NTHR; ++i) + { + thrs[i] = new RecordThread(); + thrs[i]->start(); + } + + + for (unsigned int i = 0; i < NTHR; ++i) + { + + thrs[i]->join(); + delete thrs[i]; + + } + + delete [] thrs; + + } + catch (except::Exception& ex) + { + std::cout << "Exception: " << ex.getMessage() << std::endl; + std::cout << ex.getTrace() << std::endl; + } + return 0; +} diff --git a/modules/c++/nitf/tests/test_read_acftb.cpp b/modules/c++/nitf/tests/test_read_acftb.cpp new file mode 100644 index 000000000..36ae2984b --- /dev/null +++ b/modules/c++/nitf/tests/test_read_acftb.cpp @@ -0,0 +1,131 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include +#include + +//struct TREPrintFunctor : public nitf::TRETraverser +//{ +// void operator()(nitf::TRE* tre, nitf::TREDescription* desc, +// const std::string& tag, nitf::Field field, NITF_DATA* userData) +// { +// std::cout << (desc->label ? desc->label : "null") << +// "(" << tag << ") = [" << field.toString() << "]" << std::endl; +// } +//}; + + +void findInExtensions(nitf::Extensions ext) +{ + try + { + //TREPrintFunctor treTraverser; + nitf::List l = ext.getTREsByName("ACFTB"); + nitf::ListIterator iter; + nitf::ListIterator end = l.end(); + for (iter = l.begin(); iter != end; ++iter ) + { + + nitf::TRE tre = *iter; + //tre.foreach(treTraverser); + if (tre.exists( "raw_data" ) ) + { + std::cout + << "Your plugin for ACFTB was not loaded so the data is contained in the RAW section" << std::endl; + } + else + { + try + { + // This will throw a NoSuchKeyException if + // it is not found + nitf::Field v = tre.getField( "ACMSNID" ); + std::cout << "Mission ID: [" << v.toString() << "]" << std::endl; + + } + catch (except::NoSuchKeyException& none) + { + throw nitf::NITFException(none, + Ctxt("Error: no Mission ID available")); + + } + } + } + } + catch (except::NoSuchKeyException& noACFTB) + { + std::cout << "No ACFTB" << std::endl; + return ; + } + +} + + +int main(int argc, char** argv) +{ + try + { + nitf::Reader reader; + if (argc != 2) + { + throw nitf::NITFException(Ctxt(FmtX("Usage: %s \n", + argv[0]))); + } + nitf::IOHandle io(argv[1]); + nitf::Record record = reader.read(io); + + nitf::ListIterator end = record.getImages().end(); + + for (nitf::ListIterator iter = record.getImages().begin(); + iter != end; ++iter) + { + nitf::ImageSegment imageSegment = *iter; + assert( imageSegment.isValid() ); + + if ( imageSegment.getSubheader().getUserDefinedSection().isValid() ) + { + std::cout << "ONE" << std::endl; + findInExtensions( imageSegment.getSubheader().getUserDefinedSection() ); + } + else + std::cout << "Nothing found in user defined section!" + << std::endl; + + if ( imageSegment.getSubheader().getExtendedSection().isValid() ) + { + std::cout << "TWO" << std::endl; + findInExtensions( imageSegment.getSubheader().getExtendedSection()); + } + else + std::cout << "Nothing found in extended section!" << std::endl; + + } + + } + catch (except::Throwable& t) + { + std::cout << t.getMessage() << std::endl; + std::cout << t.getTrace() << std::endl; + } + return 0; +} + diff --git a/modules/c++/nitf/tests/test_ref_counts.cpp b/modules/c++/nitf/tests/test_ref_counts.cpp new file mode 100755 index 000000000..55dd51b92 --- /dev/null +++ b/modules/c++/nitf/tests/test_ref_counts.cpp @@ -0,0 +1,70 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + +void testRecord(nitf::Reader reader) +{ + std::cout << reader.getRecord().getHeader().getFileTitle().toString() << std::endl; +} + +int main(int argc, char **argv) +{ + try + { + // This is the reader object + nitf::Reader reader; + + if (argc != 2) + { + std::cout << "Usage: " << argv[0] << " " << std::endl; + exit( EXIT_FAILURE); + } + + if (nitf::Reader::getNITFVersion(argv[1]) == NITF_VER_UNKNOWN) + { + std::cout << "This file does not appear to be a valid NITF" + << std::endl; + exit( EXIT_FAILURE); + } + + nitf::IOHandle io(argv[1]); + reader.read(io); + + testRecord(reader); + io.close(); + + for (int i = 0; i < 2000; ++i) + { + nitf::IOHandle handle(argv[1]); +// handle.close(); + } + + + return 0; + } + catch (except::Throwable& t) + { + std::cout << t.getTrace() << std::endl; + return 1; + } +} diff --git a/modules/c++/nitf/tests/test_round_trip.cpp b/modules/c++/nitf/tests/test_round_trip.cpp new file mode 100644 index 000000000..0f21b5471 --- /dev/null +++ b/modules/c++/nitf/tests/test_round_trip.cpp @@ -0,0 +1,191 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include +#include +#include +#include +#include +#include + +/* + * This test tests the round-trip process of taking an input NITF + * file and writing it to a new file. This includes writing the image + * segments (headers, extensions, and image data). This is an example + * of how users can write the image data to their NITF file + */ + +namespace +{ +class RowStreamer : public nitf::RowSourceCallback +{ +public: + RowStreamer(nitf::Uint32 band, + nitf::Uint32 numCols, + nitf::ImageReader reader) throw (nitf::NITFException) : + mReader(reader), + mBand(band) + { + mWindow.setStartRow(0); + mWindow.setNumRows(1); + mWindow.setStartCol(0); + mWindow.setNumCols(numCols); + mWindow.setBandList(&mBand); + mWindow.setNumBands(1); + } + + void nextRow(nitf::Uint32 band, char* buffer) throw (nitf::NITFException) + { + int padded; + mReader.read(mWindow, (nitf::Uint8**) &buffer, &padded); + mWindow.setStartRow(mWindow.getStartRow() + 1); + } + +private: + nitf::ImageReader mReader; + nitf::SubWindow mWindow; + nitf::Uint32 mBand; +}; + +// RAII for managing a list of RowStreamer's +class RowStreamers +{ +public: + ~RowStreamers() + { + for (size_t ii = 0; ii < mStreamers.size(); ++ii) + { + delete mStreamers[ii]; + } + } + + nitf::RowSourceCallback* add(nitf::Uint32 band, + nitf::Uint32 numCols, + nitf::ImageReader reader) + { + std::auto_ptr + streamer(new RowStreamer(band, numCols, reader)); + RowStreamer* const streamerPtr(streamer.get()); + + mStreamers.push_back(streamerPtr); + streamer.release(); + return streamerPtr; + } + +private: + std::vector mStreamers; +}; +} + +int main(int argc, char **argv) +{ + try + { + // Check argv and make sure we are happy + if (argc != 3) + { + std::cout << "Usage: %s \n" << argv[0] + << std::endl; + exit( EXIT_FAILURE); + } + + // Check that wew have a valid NITF + if (nitf::Reader::getNITFVersion(argv[1]) == NITF_VER_UNKNOWN) + { + std::cout << "Invalid NITF: " << argv[1] << std::endl; + exit( EXIT_FAILURE); + } + + //read it in + nitf::Reader reader; + nitf::IOHandle io(argv[1]); + nitf::Record record = reader.read(io); + + //now, let's create the writer + nitf::Writer writer; + nitf::IOHandle output(argv[2], NITF_ACCESS_WRITEONLY, NITF_CREATE); + writer.prepare(output, record); + + nitf::ListIterator iter = record.getImages().begin(); + nitf::Uint32 num = record.getNumImages(); + RowStreamers rowStreamers; + for (nitf::Uint32 i = 0; i < num; i++) + { + //for the images, we'll use a RowSource for streaming + nitf::ImageSegment imseg = *iter; + iter++; + nitf::ImageReader iReader = reader.newImageReader(i); + nitf::ImageWriter iWriter = writer.newImageWriter(i); + nitf::ImageSource iSource; + nitf::Uint32 nBands = imseg.getSubheader().getNumImageBands(); + nitf::Uint32 nRows = imseg.getSubheader().getNumRows(); + nitf::Uint32 nCols = imseg.getSubheader().getNumCols(); + nitf::Uint32 pixelSize = NITF_NBPP_TO_BYTES( + imseg.getSubheader().getNumBitsPerPixel()); + + for (nitf::Uint32 i = 0; i < nBands; i++) + { + nitf::RowSource rowSource(i, nRows, nCols, pixelSize, + rowStreamers.add(i, nCols, iReader)); + iSource.addBand(rowSource); + } + iWriter.attachSource(iSource); + } + + num = record.getNumGraphics(); + for (nitf::Uint32 i = 0; i < num; i++) + { + nitf::SegmentReaderSource readerSource(reader.newGraphicReader(i)); + mem::SharedPtr< ::nitf::WriteHandler> segmentWriter( + new nitf::SegmentWriter(readerSource)); + writer.setGraphicWriteHandler(i, segmentWriter); + } + + num = record.getNumTexts(); + for (nitf::Uint32 i = 0; i < num; i++) + { + nitf::SegmentReaderSource readerSource(reader.newTextReader(i)); + mem::SharedPtr< ::nitf::WriteHandler> segmentWriter( + new nitf::SegmentWriter(readerSource)); + writer.setTextWriteHandler(i, segmentWriter); + } + + num = record.getNumDataExtensions(); + for (nitf::Uint32 i = 0; i < num; i++) + { + nitf::SegmentReaderSource readerSource(reader.newDEReader(i)); + mem::SharedPtr< ::nitf::WriteHandler> segmentWriter( + new nitf::SegmentWriter(readerSource)); + writer.setDEWriteHandler(i, segmentWriter); + } + + writer.write(); + output.close(); + io.close(); + return 0; + } + catch (except::Throwable & t) + { + std::cout << "ERROR!: " << t.toString() << std::endl; + } +} + diff --git a/modules/c++/nitf/tests/test_static_plugin.cpp b/modules/c++/nitf/tests/test_static_plugin.cpp new file mode 100644 index 000000000..34e82506a --- /dev/null +++ b/modules/c++/nitf/tests/test_static_plugin.cpp @@ -0,0 +1,47 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + +NITF_TRE_STATIC_HANDLER_REF(PIAPEA); + +int main(int argc, char** argv) +{ + try + { + nitf::PluginRegistry::registerTREHandler(PIAPEA_init, PIAPEA_handler); + nitf::TRE tre("PIAPEA"); + + std::cout << "== PIAPEA TRE ==" << std::endl; + for (nitf::TRE::Iterator it = tre.begin(); it != tre.end(); ++it) + { + std::cout << (*it).getKey() << ": [" << + nitf::Field((*it).getData()).toString() << "]" << std::endl; + } + return 0; + } + catch (except::Throwable& t) + { + std::cout << t.getTrace() << std::endl; + } + return 1; +} diff --git a/modules/c++/nitf/tests/test_tre_mods++.cpp b/modules/c++/nitf/tests/test_tre_mods++.cpp new file mode 100644 index 000000000..824bdbf0f --- /dev/null +++ b/modules/c++/nitf/tests/test_tre_mods++.cpp @@ -0,0 +1,114 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include +#include + +/* This test should be used to verify the TRE modifications work. + * It probably should not be added to a core canon of tests, but + * it is useful to test any changes with the TRE API + */ +int main(int argc, char **argv) +{ + try + { + std::string divider( + "---------------------------------------------------------"); + + //create an ACFTA TRE + nitf::TRE tre("ACFTA"); + //tre.print(); //print it + std::cout << divider << std::endl; + + //set a field + tre.setField("AC_MSN_ID", "fly-by"); + //tre.print(); + std::cout << divider << std::endl; + + //re-set the field + tre.setField("AC_MSN_ID", 1.2345678); + //tre.print(); + std::cout << divider << std::endl; + + //try setting an invalid tag + try + { + tre.setField("invalid-tag", "some data"); + } + catch (except::Throwable & t) + { + std::cout << t.getMessage() << std::endl; + } + + // Now, try to create a SANE TRE + tre = nitf::TRE("JITCID"); + tre.setField("FILCMT", "fyi"); + //tre.print(); + std::cout << divider << std::endl; + + //is sane? + //std::cout << "Is Sane? " << (tre.isSane() ? "yes" : "no") << std::endl; + + // try cloning the tre + nitf::TRE dolly = tre.clone(); + //dolly.print(); + std::cout << divider << std::endl; + + //the two should NOT be equal -- underlying object is different + std::cout << "Equal? : " << (tre == dolly ? "yes" : "no") << std::endl; + + //is dolly sane? + //std::cout << "Is Sane? " << (dolly.isSane() ? "yes" : "no") << std::endl; + + + //let's try getting the TREDescriptions ourselves + +/* nitf::TREDescriptionInfo *infoPtr = NULL; + nitf::TREDescriptionSet *descriptions = + nitf::TRE::getTREDescriptionSet("ACFTA"); + int numDescriptions = 0; + infoPtr = descriptions->descriptions; + while (infoPtr && (infoPtr->description != NULL)) + { + numDescriptions++; + infoPtr++; + } + std::cout << "Found " << numDescriptions << " descriptions for ACFTA" << std::endl; + + infoPtr = descriptions->descriptions; + while (infoPtr && (infoPtr->description != NULL)) + { + std::cout << "Name: " << infoPtr->name << ", Length: " << + infoPtr->lengthMatch << std::endl << divider << std::endl; + tre = nitf::TRE("ACFTA", infoPtr->description); + tre.print(); + std::cout << divider << std::endl; + infoPtr++; + } +*/ + } + catch (except::Throwable & t) + { + std::cout << t.getMessage() << std::endl; + } + return 0; +} diff --git a/modules/c++/nitf/tests/test_writer_3++.cpp b/modules/c++/nitf/tests/test_writer_3++.cpp new file mode 100644 index 000000000..c233c86d2 --- /dev/null +++ b/modules/c++/nitf/tests/test_writer_3++.cpp @@ -0,0 +1,234 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include +#include +#include + +/* + * This test tests the round-trip process of taking an input NITF + * file and writing it to a new file. This includes writing the image + * segments (headers, extensions, and image data). This is an example + * of how users can write the image data to their NITF file + */ + +nitf::Record doRead(const std::string& inFile); + +std::string makeBandName(const std::string& rootFile, int imageNum, int bandNum) +{ + std::string::size_type pos = rootFile.find_last_of("/\\"); + std::ostringstream os; + os << rootFile.substr(pos + 1) << "__" << imageNum << "_band_" << bandNum; + std::string newFile = os.str(); + + while ((pos = newFile.find(".")) != std::string::npos) + newFile.replace(pos, 1, "_"); + newFile += ".man"; + return newFile; +} + +nitf::ImageSource setupBands(int nbands, int imageNum, const std::string& inRootFile) +{ + nitf::ImageSource iSource; + for (int i = 0; i < nbands; i++) + { + std::string inFile = makeBandName(inRootFile, imageNum, i); + nitf::FileSource fs(inFile, 0, 1, 0); + iSource.addBand(fs); + } + return iSource; +} + +void doWrite(nitf::Record record, const std::string& inRootFile, const std::string& outFile) +{ + nitf::Writer writer; + nitf::IOHandle output(outFile, NITF_ACCESS_WRITEONLY, NITF_CREATE); + writer.prepare(output, record); + + int numImages = record.getHeader().getNumImages(); + nitf::ListIterator end = record.getImages().end(); + nitf::ListIterator iter = record.getImages().begin(); + + for (int i = 0; i < numImages && iter != end; ++i, ++iter) + { + nitf::ImageSegment imseg; + imseg = *iter; + int nbands = imseg.getSubheader().getNumImageBands(); + nitf::ImageWriter iWriter = writer.newImageWriter(i); + nitf::ImageSource iSource = setupBands(nbands, i, inRootFile); + iWriter.attachSource(iSource); + } + writer.write(); + output.close(); +} + +int main(int argc, char **argv) +{ + try + { + // Check argv and make sure we are happy + if (argc != 3) + { + std::cout << "Usage: " << argv[0] + << " \n\n"; + exit(EXIT_FAILURE); + } + + // Check that wew have a valid NITF + if (nitf::Reader::getNITFVersion(argv[1]) == NITF_VER_UNKNOWN ) + { + std::cout << "Invalid NITF: " << argv[1] << std::endl; + exit(EXIT_FAILURE); + } + + nitf::Record record = doRead(argv[1]); + doWrite(record, argv[1], argv[2]); + return 0; + } + catch (except::Throwable & t) + { + std::cout << t.getMessage() << std::endl; + } +} + + +void manuallyWriteImageBands(nitf::ImageSegment & segment, + const std::string& imageName, + nitf::ImageReader& deserializer, + int imageNumber) +{ + int padded; + + nitf::ImageSubheader subheader = segment.getSubheader(); + + + nitf::Uint32 nBits = subheader.getNumBitsPerPixel(); + nitf::Uint32 nBands = subheader.getNumImageBands(); + nitf::Uint32 xBands = subheader.getNumMultispectralImageBands(); + nBands += xBands; + + nitf::Uint32 nRows = subheader.getNumRows(); + nitf::Uint32 nColumns = subheader.getNumCols(); + + //one row at a time + size_t subWindowSize = nColumns * NITF_NBPP_TO_BYTES(nBits); + + std::cout << "NBANDS -> " << nBands << std::endl + << "XBANDS -> " << xBands << std::endl + << "NROWS -> " << nRows << std::endl + << "NCOLS -> " << nColumns << std::endl + << "PVTYPE -> " << subheader.getPixelValueType().toString() << std::endl + << "NBPP -> " << subheader.getNumBitsPerPixel().toString() << std::endl + << "ABPP -> " << subheader.getActualBitsPerPixel().toString() << std::endl + << "PJUST -> " << subheader.getPixelJustification().toString() << std::endl + << "IMODE -> " << subheader.getImageMode().toString() << std::endl + << "NBPR -> " << subheader.getNumBlocksPerRow().toString() << std::endl + << "NBPC -> " << subheader.getNumBlocksPerCol().toString() << std::endl + << "NPPBH -> " << (int)subheader.getNumPixelsPerHorizBlock() << std::endl + << "NPPBV -> " << (int)subheader.getNumPixelsPerVertBlock() << std::endl + << "IC -> " << subheader.getImageCompression().toString() << std::endl + << "COMRAT -> " << subheader.getCompressionRate().toString() << std::endl; + + nitf::Uint8** buffer = new nitf::Uint8*[nBands]; + nitf::Uint32* bandList = new nitf::Uint32[nBands]; + + for (nitf::Uint32 band = 0; band < nBands; band++) + bandList[band] = band; + + nitf::SubWindow subWindow; + subWindow.setStartCol(0); + subWindow.setNumRows(1); + subWindow.setNumCols(nColumns); + + // necessary ? + nitf::DownSampler* pixelSkip = new nitf::PixelSkip(1, 1); + subWindow.setDownSampler(pixelSkip); + subWindow.setBandList(bandList); + subWindow.setNumBands(nBands); + + assert(buffer); + for (nitf::Uint32 i = 0; i < nBands; i++) + { + buffer[i] = new nitf::Uint8[subWindowSize]; + assert(buffer[i]); + } + + std::vector handles; + //make the files + for (nitf::Uint32 i = 0; i < nBands; i++) + { + std::string name = makeBandName(imageName, imageNumber, i); + nitf::IOHandle toFile(name, NITF_ACCESS_WRITEONLY, NITF_CREATE); + handles.push_back(toFile); + } + + //read all row blocks and write to disk + for (nitf::Uint32 i = 0; i < nRows; ++i) + { + subWindow.setStartRow(i); + deserializer.read(subWindow, buffer, &padded); + for (nitf::Uint32 j = 0; j < nBands; j++) + { + handles[j].write((const char*)buffer[j], subWindowSize); + } + } + + //close output handles + for (nitf::Uint32 i = 0; i < nBands; i++) + handles[i].close(); + + /* free buffers */ + for (nitf::Uint32 i = 0; i < nBands; i++) + delete [] buffer[i]; + delete [] buffer; + delete [] bandList; + delete pixelSkip; +} + + +nitf::Record doRead(const std::string& inFile) +{ + nitf::Reader reader; + nitf::IOHandle io(inFile); + nitf::Record record = reader.read(io); + + /* Set this to the end, so we'll know when we're done! */ + nitf::ListIterator iter = record.getImages().begin(); + + + nitf::Uint32 num = record.getNumImages(); + + for (nitf::Uint32 i = 0; i < num; i++) + { + nitf::ImageSegment imageSegment = *iter; + iter++; + nitf::ImageReader deserializer = reader.newImageReader(i); + std::cout << "Writing image " << i << "..." << std::endl; + + /* Write the thing out */ + manuallyWriteImageBands(imageSegment, inFile, deserializer, i); + std::cout << "done.\n" << std::endl; + } + + + return record; +} diff --git a/modules/c++/nitf/tests/test_writer_4.cpp b/modules/c++/nitf/tests/test_writer_4.cpp new file mode 100644 index 000000000..25aa42ae9 --- /dev/null +++ b/modules/c++/nitf/tests/test_writer_4.cpp @@ -0,0 +1,92 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include +#include +#include +#include + +int main(int argc, char **argv) +{ + try + { + if (argc != 3) + { + std::cout << "Usage: " << argv[0] + << " \n\n"; + exit(EXIT_FAILURE); + } + + //create a Reader and read in the Record + nitf::Reader reader; + nitf::IOHandle input(argv[1]); + nitf::Record record = reader.read(input); + + //create a Writer and prepare it for the Record + nitf::IOHandle output(argv[2], NITF_ACCESS_WRITEONLY, NITF_CREATE); + nitf::Writer writer; + writer.prepare(output, record); + + //go through and setup the pass-through writehandlers + nitf::List images = record.getImages(); + for (int i = 0, num = record.getHeader().getNumImages(); i < num; ++i) + { + nitf::ImageSegment segment = images[i]; + long offset = segment.getImageOffset(); + mem::SharedPtr< ::nitf::WriteHandler> handler( + new nitf::StreamIOWriteHandler ( + input, offset, segment.getImageEnd() - offset)); + writer.setImageWriteHandler(i, handler); + } + + nitf::List graphics = record.getImages(); + for (int i = 0, num = record.getHeader().getNumGraphics(); i < num; ++i) + { + nitf::GraphicSegment segment = graphics[i]; + long offset = segment.getOffset(); + mem::SharedPtr< ::nitf::WriteHandler> handler( + new nitf::StreamIOWriteHandler ( + input, offset, segment.getEnd() - offset)); + writer.setGraphicWriteHandler(i, handler); + } + + nitf::List texts = record.getTexts(); + for (int i = 0, num = record.getHeader().getNumTexts(); i < num; ++i) + { + nitf::TextSegment segment = texts[i]; + long offset = segment.getOffset(); + mem::SharedPtr< ::nitf::WriteHandler> handler( + new nitf::StreamIOWriteHandler ( + input, offset, segment.getEnd() - offset)); + writer.setTextWriteHandler(i, handler); + } + + //once everything is set, write it! + writer.write(); + input.close(); + output.close(); + } + catch (except::Throwable & t) + { + std::cout << t.getMessage() << std::endl; + } +} diff --git a/modules/c++/nitf/tests/test_writer_5.cpp b/modules/c++/nitf/tests/test_writer_5.cpp new file mode 100644 index 000000000..b39ccc1fa --- /dev/null +++ b/modules/c++/nitf/tests/test_writer_5.cpp @@ -0,0 +1,81 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include +#include +#include +#include +#include +#include + +int main(int argc, char **argv) +{ + try + { + if (argc != 3) + { + std::cout << "Usage: " << argv[0] + << " \n\n"; + exit(EXIT_FAILURE); + } + + //create a Reader and read in the Record + nitf::Reader reader; + nitf::IOHandle input(argv[1]); + nitf::Record record = reader.read(input); + + //create a Writer and prepare it for the Record + nitf::Uint32 numOfBytes = (nitf::Uint32)record.getHeader().getFileLength(); + std::vector outBufVec(numOfBytes); + char* const outBuf(outBufVec.empty() ? NULL : &outBufVec[0]); + nitf::MemoryIO memOutput(outBuf, numOfBytes, false); + + nitf::Writer memWriter; + memWriter.prepareIO(memOutput, record); + + //go through and setup the pass-through writehandlers + nitf::List images = record.getImages(); + for (int i = 0, num = record.getHeader().getNumImages(); i < num; ++i) + { + nitf::ImageSegment segment = images[i]; + long offset = segment.getImageOffset(); + mem::SharedPtr< ::nitf::WriteHandler> handler( + new nitf::StreamIOWriteHandler ( + input, offset, segment.getImageEnd() - offset)); + memWriter.setImageWriteHandler(i, handler); + } + + //once everything is set, write it! + memWriter.write(); + + std::ofstream outfile (argv[2],std::ofstream::binary); + outfile.write(outBuf, numOfBytes); + outfile.close(); + + input.close(); + memOutput.close(); + } + catch (except::Throwable & t) + { + std::cout << t.getMessage() << std::endl; + } +} diff --git a/modules/c++/nitf/wscript b/modules/c++/nitf/wscript new file mode 100644 index 000000000..2bf7b0a02 --- /dev/null +++ b/modules/c++/nitf/wscript @@ -0,0 +1,24 @@ +from os.path import split, basename, splitext + +NAME = 'nitf' +MAINTAINER = 'asylvest@users.sourceforge.net' +VERSION = '2.7' +MODULE_DEPS = 'mt sys mem' +USELIB = 'THREAD DL' +USELIB_LOCAL = 'nitf-c' +LANG = 'c++' +TEST_FILTER = 'test_functional.cpp test_handles.cpp ' \ + 'test_mem_source.cpp test_static_plugin.cpp' +APPS = 'apps/show_nitf++.cpp' + +options = configure = distclean = lambda p: None + +def build(bld): + bld.module(**globals()) + + env = bld.get_env() + for app in APPS.split() : + bld.program_helper(module_deps=NAME, + source=app, path=bld.path, + name=splitext(basename(app))[0]) + diff --git a/modules/c++/str/README.txt b/modules/c++/str/README.txt new file mode 100644 index 000000000..e4d969894 --- /dev/null +++ b/modules/c++/str/README.txt @@ -0,0 +1,6 @@ +The str library contains functions and classes that can be used for +doing string manipulations. Tokenizing and formatting functions +are mostly the concentration here. + +This library requires except. + diff --git a/modules/c++/str/include/import/str.h b/modules/c++/str/include/import/str.h new file mode 100644 index 000000000..43ebee45a --- /dev/null +++ b/modules/c++/str/include/import/str.h @@ -0,0 +1,50 @@ +/* ========================================================================= + * This file is part of str-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * str-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __IMPORT_STR_H__ +#define __IMPORT_STR_H__ + +/*! + * \file str.h + * \brief The str module includes all objects for string manipulation + * + * When performing string operations, it is sometimes the case that the + * Standard Library std::string class is simply not enough. The str + * module is a conglomeration of useful string manipulations including + * a Tokenizer class and a c-style formatting functions. + * + * This library is intended to compliment the STL while providing additional + * functionality that the standard lacks + * + * + */ + +#include "str/Convert.h" +#include "str/Tokenizer.h" +#include "str/Format.h" +#include "str/Manip.h" +#define STR_MAJOR_VERSION 0 +#define STR_MINOR_VERSION 1 +#define STR_MICRO_VERSION 0 + +#endif diff --git a/modules/c++/str/include/str/Convert.h b/modules/c++/str/include/str/Convert.h new file mode 100644 index 000000000..b93a42a2c --- /dev/null +++ b/modules/c++/str/include/str/Convert.h @@ -0,0 +1,181 @@ +/* ========================================================================= + * This file is part of str-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2011, General Dynamics - Advanced Information Systems + * + * str-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __STR_CONVERT_H__ +#define __STR_CONVERT_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace str +{ + +template int getPrecision(const T& type); +template int getPrecision(const std::complex& type); + +template std::string toString(const T& value) +{ + std::ostringstream buf; + buf.precision(str::getPrecision(value)); + buf << std::boolalpha << value; + return buf.str(); +} + +template std::string toString(const T& real, const T& imag) +{ + return toString(std::complex(real, imag)); +} + +template T toType(const std::string& s) +{ + if (s.empty()) + throw except::BadCastException(except::Context(__FILE__, __LINE__, + std::string(""), std::string(""), std::string("Empty string"))); + + T value; + + std::stringstream buf(s); + buf.precision(str::getPrecision(value)); + buf >> value; + + if (buf.fail()) + { + throw except::BadCastException(except::Context(__FILE__, __LINE__, + std::string(""), std::string(""), + std::string("Conversion failed: '") + + s + std::string("' -> ") + typeid(T).name())); + } + + return value; +} + +template<> bool toType (const std::string& s); +template<> std::string toType (const std::string& s); + +/** + * strtoll wrapper for msvc compatibility. + */ +long long strtoll(const char *str, char **endptr, int base); +/** + * strtoull wrapper for msvc compatibility. + */ +unsigned long long strtoull(const char *str, char **endptr, int base); + +/** + * Convert a string containing a number in any base to a numerical type. + * + * @param s a string containing a number in base base + * @param base the base of the number in s + * @return a numberical representation of the number + * @throw BadCastException thrown if cast cannot be performed. + */ +template T toType(const std::string& s, int base) +{ + char* end; + errno = 0; + const char* str = s.c_str(); + + T res; + bool overflow = false; + if (std::numeric_limits::is_signed) + { + const long long longRes = str::strtoll(str, &end, base); + if ((T)longRes < std::numeric_limits::min() || + (T)longRes > std::numeric_limits::max()) + { + overflow = true; + } + res = static_cast(longRes); + } + else + { + const unsigned long long longRes = str::strtoull(str, &end, base); + if ((T)longRes < std::numeric_limits::min() || + (T)longRes > std::numeric_limits::max()) + { + overflow = true; + } + res = static_cast(longRes); + } + + if (overflow || errno == ERANGE) + throw except::BadCastException(except::Context(__FILE__, __LINE__, + std::string(""), std::string(""), + std::string("Overflow: '") + + s + std::string("' -> ") + typeid(T).name())); + // If the end pointer is at the start of the string, we didn't convert anything. + else if (end == str) + throw except::BadCastException(except::Context(__FILE__, __LINE__, + std::string(""), std::string(""), + std::string("Conversion failed: '") + + s + std::string("' -> ") + typeid(T).name())); + + return res; +} + +/** + * Determine the precision required for the data type. + * + * @param type A variable of the type whose precision argument is desired. + * @return The integer argument required by ios::precision() to represent + * this type. + */ +template int getPrecision(const T& ) +{ + return 0; +} +template int getPrecision(const std::complex& type) +{ + return getPrecision(type.real()); +} + +template<> int getPrecision(const float& type); +template<> int getPrecision(const double& type); +template<> int getPrecision(const long double& type); + +/** Generic casting routine; used by explicitly overloaded + conversion operators. + + @param value A variable of the type being cast to. + @return The internal representation of GenericType, converted + to the desired type, if possible. + @throw BadCastException thrown if cast cannot be performed. + */ +template +T generic_cast(const std::string& value) throw (except::BadCastException) +{ + return str::toType(value); +} + +} + +#endif diff --git a/modules/c++/str/include/str/Format.h b/modules/c++/str/include/str/Format.h new file mode 100644 index 000000000..b12db464d --- /dev/null +++ b/modules/c++/str/include/str/Format.h @@ -0,0 +1,59 @@ +/* ========================================================================= + * This file is part of str-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2011, General Dynamics - Advanced Information Systems + * + * str-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __STR_FORMAT_H__ +#define __STR_FORMAT_H__ + +#include +#include + +namespace str +{ + +/*! + * \param format The format + * \param ... Any printf like thing + */ +std::string format(const char *format, ...); + +class Format +{ +public: + Format(const char* format, ...); + + operator std::string() const + { + return mString; + } + + operator std::string& () + { + return mString; + } + +protected: + std::string mString; +}; + +} +#endif diff --git a/modules/c++/str/include/str/Manip.h b/modules/c++/str/include/str/Manip.h new file mode 100644 index 000000000..ef98bb7fd --- /dev/null +++ b/modules/c++/str/include/str/Manip.h @@ -0,0 +1,166 @@ +/* ========================================================================= + * This file is part of str-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2011, General Dynamics - Advanced Information Systems + * + * str-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __STR_MANIP_H__ +#define __STR_MANIP_H__ + +#include +#include +#include +#include "str/Convert.h" + +namespace str +{ +/** + * Trim the white space off the back and front of a string + * @param s String to trim + */ +void trim(std::string& s); + +/** + * Checks the end of s with match + * @param s String to check + * @param match String to compare with + * @return true if it matches, otherwise false + */ +bool endsWith(const std::string& s, const std::string& match); + +/** + * Checks the start of s with match + * @param s String to check + * @param s String to compare with + * @return true if it matches, otherwise false + */ +bool startsWith(const std::string& s, const std::string& match); + +/** + * finds the first instance of "search" and + * substitutes it for "replace", it then returns + * the start of search, so you can loop and replace + * all instances of "search". + * @param str String to check + * @param search String to search for + * @param replace String to replace with + * @param start starting position to start search + * @return position of first find, str.length() if not found + */ +size_t replace(std::string& str, + const std::string& search, + const std::string& replace, + size_t start = 0); + +/** + * finds all instances of "search" and + * substitutes them for "replace" + * @param string String to check + * @param search String to search for + * @param replace String to replace with + */ +void replaceAll(std::string& string, + const std::string& search, + const std::string& replace); + +/** + * Returns true if the string contains the match + */ +bool contains(const std::string& str, const std::string& match); + + +/** + * Returns true if the string contains only letters. + */ +bool isAlpha(const std::string& s); + +/** + * Returns true if the string contains only letters and spaces. + */ +bool isAlphaSpace(const std::string& s); + +/** + * Returns true if the string contains only digits. This does not include + * decimal points. + */ +bool isNumeric(const std::string& s); + +/** + * Returns true if the string contains only digits and spaces. + */ +bool isNumericSpace(const std::string& s); + +/** + * Returns true if the string contains only whitespace characters (or empty). + */ +bool isWhitespace(const std::string& s); + +/** + * Returns true if the string contains only letters and digits. + */ +bool isAlphanumeric(const std::string& s); + +/** + * Returns true if the string contains only ASCII printable characters. + */ +bool isAsciiPrintable(const std::string& s); + +/** + * Returns true if the string contains only the given allowed characters. + */ +bool containsOnly(const std::string& s, const std::string& validChars); + +/** + * Splits a string based on a splitter string. Similar to tokenization, except + * the splitter string can be of any length. + * @param s String to check + * @param splitter String to split upon + * @return vector of strings + */ +std::vector split(const std::string& s, + const std::string& splitter = " ", + size_t maxSplit = std::string::npos); + +//! Uses std::transform to convert all chars to lower case +void lower(std::string& s); + +//! Uses std::transform to convert all chars to upper case +void upper(std::string& s); + +template +std::string join(std::vector toks, std::string with) +{ + if (toks.empty()) + return ""; + + int len = (int)toks.size(); + std::ostringstream oss; + int i = 0; + for (; i < len - 1; i++) + { + oss << str::toString(toks[i]) << with; + } + oss << str::toString(toks[i]); + return oss.str(); +} + + +} + +#endif diff --git a/modules/c++/str/include/str/Tokenizer.h b/modules/c++/str/include/str/Tokenizer.h new file mode 100644 index 000000000..8c61242b7 --- /dev/null +++ b/modules/c++/str/include/str/Tokenizer.h @@ -0,0 +1,77 @@ +/* ========================================================================= + * This file is part of str-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * str-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __STR_TOKENIZER_H__ +#define __STR_TOKENIZER_H__ + +/*! + * \file Tokenizer.h + * \brief A class functor for string tokenization + * + * Provides the implemenation of the Tokenizer class, which is + * a function object that can do tokenization base on a delimiter + * + */ + +#include +#include + +namespace str +{ + +/*! + * \class Tokenizer + * \brief A class functor for string tokenization + * + * By specifying a set of delimiters and an input string, + * the user can tokenize using this method. + * example: vector v = Tokenizer(str, ";"); + * + * + */ + +class Tokenizer +{ +public: + typedef std::vector Tokens; + /*! + * Constructor. Take a string to parse, and a delimiter set + * \param str String to parse + * \param delim string to divide str up using + */ + Tokenizer(const std::string& str, const std::string& delim); + + /*! + * Method to return the resultant vector + * \return The vector that was created by the tokenizer + */ + operator Tokenizer::Tokens& () + { + return vec; + } +protected: + Tokenizer::Tokens vec; +}; + +} +#endif diff --git a/modules/c++/str/source/Convert.cpp b/modules/c++/str/source/Convert.cpp new file mode 100644 index 000000000..d017e341a --- /dev/null +++ b/modules/c++/str/source/Convert.cpp @@ -0,0 +1,89 @@ +/* ========================================================================= + * This file is part of str-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2011, General Dynamics - Advanced Information Systems + * + * str-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include "str/Convert.h" +#include "str/Manip.h" + +template<> std::string str::toType(const std::string& s) +{ + return s; +} +template<> bool str::toType(const std::string& s) +{ + std::string ss = s; + str::lower(ss); + + if (ss == "true") + { + return true; + } + else if (ss == "false") + { + return false; + } + else if (str::isNumeric(ss)) + { + int value(0); + std::stringstream buf(ss); + buf >> value; + return (value != 0); + } + else + { + throw except::BadCastException(except::Context(__FILE__, __LINE__, + std::string(""), std::string(""), + std::string("Invalid bool: '") + s + std::string("'"))); + } + + return false; +} + +long long str::strtoll(const char *str, char **endptr, int base) +{ +#if defined(_MSC_VER) + return _strtoi64(str, endptr, base); +#else + return ::strtoll(str, endptr, base); +#endif +} + +unsigned long long str::strtoull(const char *str, char **endptr, int base) +{ +#if defined(_MSC_VER) + return _strtoui64(str, endptr, base); +#else + return ::strtoull(str, endptr, base); +#endif +} + +template<> int str::getPrecision(const float& ) +{ + return std::numeric_limits::digits10 + 1; +} +template<> int str::getPrecision(const double& ) +{ + return std::numeric_limits::digits10 + 1; +} +template<> int str::getPrecision(const long double& ) +{ + return std::numeric_limits::digits10 + 1; +} diff --git a/modules/c++/str/source/Format.cpp b/modules/c++/str/source/Format.cpp new file mode 100644 index 000000000..3671911a8 --- /dev/null +++ b/modules/c++/str/source/Format.cpp @@ -0,0 +1,45 @@ +/* ========================================================================= + * This file is part of str-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2011, General Dynamics - Advanced Information Systems + * + * str-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#include "str/Format.h" +#include + +std::string str::format(const char *format, ...) +{ + char buffer[1024]; + va_list args; + va_start(args, format); + vsprintf(buffer, format, args); + va_end(args); + return std::string(buffer); +} + +str::Format::Format(const char* format, ...) +{ + char buffer[1024]; + va_list args; + va_start(args, format); + vsprintf(buffer, format, args); + va_end(args); + mString = buffer; +} diff --git a/modules/c++/str/source/Manip.cpp b/modules/c++/str/source/Manip.cpp new file mode 100644 index 000000000..a6221f495 --- /dev/null +++ b/modules/c++/str/source/Manip.cpp @@ -0,0 +1,235 @@ +/* ========================================================================= + * This file is part of str-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2011, General Dynamics - Advanced Information Systems + * + * str-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include "str/Manip.h" +#include +#include +#include + +void str::trim(std::string & s) +{ + unsigned int i; + for (i = 0; i < s.length(); i++) + { + if (!isspace(s[i])) + break; + } + s.erase(0, i); + + for (i = s.length() - 1; (int) i >= 0; i--) + { + if (!isspace(s[i])) + break; + + } + if (i + 1 < s.length()) + s.erase(i + 1); +} + +bool str::endsWith(const std::string & s, const std::string & match) +{ + int mLen = match.length(); + int sLen = s.length(); + for (int i = 0; i < sLen && i < mLen; ++i) + if (!(s[sLen - i - 1] == match[mLen - i - 1])) + return false; + return sLen >= mLen; +} + +bool str::startsWith(const std::string & s, const std::string & match) +{ + int mLen = match.length(); + int sLen = s.length(); + for (int i = 0; i < sLen && i < mLen; ++i) + if (!(s[i] == match[i])) + return false; + return sLen >= mLen; +} + +size_t str::replace(std::string& str, + const std::string& search, + const std::string& replace, + size_t start) +{ + size_t index = str.find(search, start); + + if (index != std::string::npos) + { + str.replace(index, search.length(), replace); + start = index; + } + else + { + start = str.length(); + } + + return start; +} + +void str::replaceAll(std::string& string, + const std::string& search, + const std::string& replace) +{ + size_t start = 0; + while (start < string.length()) + { + start = str::replace(string, + search, + replace, + start); + // skip ahead -- + // avoids inifinite loop if replace contains search + start += replace.length(); + } +} + +bool str::contains(const std::string& str, const std::string& match) +{ + return str.find(match) != std::string::npos; +} + +bool str::isAlpha(const std::string& s) +{ + typedef std::string::const_iterator StringIter; + for (StringIter it = s.begin(); it != s.end(); ++it) + { + if (!isalpha(*it)) + return false; + } + return !s.empty(); +} + +bool str::isAlphaSpace(const std::string& s) +{ + typedef std::string::const_iterator StringIter; + for (StringIter it = s.begin(); it != s.end(); ++it) + { + if (!isalpha(*it) && *it != ' ') + return false; + } + return !s.empty(); +} + +bool str::isNumeric(const std::string& s) +{ + typedef std::string::const_iterator StringIter; + for (StringIter it = s.begin(); it != s.end(); ++it) + { + if (!isdigit(*it)) + return false; + } + return !s.empty(); +} + +bool str::isNumericSpace(const std::string& s) +{ + typedef std::string::const_iterator StringIter; + for (StringIter it = s.begin(); it != s.end(); ++it) + { + if (!isdigit(*it) && *it != ' ') + return false; + } + return !s.empty(); +} + +bool str::isWhitespace(const std::string& s) +{ + typedef std::string::const_iterator StringIter; + for (StringIter it = s.begin(); it != s.end(); ++it) + { + if (!isspace(*it)) + return false; + } + return true; +} + +bool str::isAlphanumeric(const std::string& s) +{ + typedef std::string::const_iterator StringIter; + for (StringIter it = s.begin(); it != s.end(); ++it) + { + if (!isalpha(*it) && !isdigit(*it)) + return false; + } + return !s.empty(); +} + +bool str::isAsciiPrintable(const std::string& s) +{ + typedef std::string::const_iterator StringIter; + for (StringIter it = s.begin(); it != s.end(); ++it) + { + char c = *it; + if (c < 32 || c > 126) + return false; + } + return true; +} + +bool str::containsOnly(const std::string& s, const std::string& validChars) +{ + typedef std::string::const_iterator StringIter; + std::vector chars(255, false); + for (StringIter it = validChars.begin(); it != validChars.end(); ++it) + chars[(unsigned int)*it] = true; + for (StringIter it = s.begin(); it != s.end(); ++it) + if (!chars[(unsigned int)*it]) + return false; + return true; +} + +std::vector str::split(const std::string& s, + const std::string& splitter, size_t maxSplit) +{ + std::vector < std::string > vec; + int str_l = (int) s.length(); + int split_l = (int) splitter.length(); + int pos = 0; + int nextPos; + while (pos < str_l && maxSplit != 1) + { + nextPos = (int) s.find(splitter, pos); + if (nextPos == (int)std::string::npos) + nextPos = str_l; + if (nextPos != pos) + vec.push_back(s.substr(pos, nextPos - pos)); + pos = nextPos + split_l; + if (maxSplit != std::string::npos && vec.size() >= maxSplit - 1) + break; + } + + if (pos < str_l) + vec.push_back(s.substr(pos)); + + return vec; +} + +void str::lower(std::string& s) +{ + std::transform(s.begin(), s.end(), s.begin(), (int(*)(int)) tolower); +} + +void str::upper(std::string& s) +{ + std::transform(s.begin(), s.end(), s.begin(), (int(*)(int)) toupper); +} + diff --git a/modules/c++/str/source/Tokenizer.cpp b/modules/c++/str/source/Tokenizer.cpp new file mode 100644 index 000000000..c48349dac --- /dev/null +++ b/modules/c++/str/source/Tokenizer.cpp @@ -0,0 +1,49 @@ +/* ========================================================================= + * This file is part of str-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2011, General Dynamics - Advanced Information Systems + * + * str-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#include "str/Tokenizer.h" + + +str::Tokenizer::Tokenizer(const std::string& str, const std::string& delim) +{ + int str_l = (int)str.length(); + int pos = 0; + int start, end; + while (true) + { + start = (int)str.find_first_not_of(delim, pos); + if (start == (int)std::string::npos) + { + break; + } + end = (int)str.find_first_of(delim, start); + if (end == (int)std::string::npos) + { + end = str_l; + } + vec.push_back(str.substr(start, end - start)); + pos = end; + + } + +} diff --git a/modules/c++/str/tests/ConvertTest.cpp b/modules/c++/str/tests/ConvertTest.cpp new file mode 100644 index 000000000..aa40c5d12 --- /dev/null +++ b/modules/c++/str/tests/ConvertTest.cpp @@ -0,0 +1,87 @@ +/* ========================================================================= + * This file is part of str-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2011, General Dynamics - Advanced Information Systems + * + * str-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include +#include + + +template void testType(const std::string& s) +{ + try + { + std::cout << str::toType(s); + } + catch (except::Exception& e) + { + std::cout << e.toString(); + } + catch (std::exception& ex) + { + std::cout << ex.what(); + } + catch (...) + { + std::cout << "Caught something"; + } +} + +int main() +{ + std::string val("0"); + + std::cout << "int: "; + testType(val); + + std::cout << std::endl << "long: "; + testType(val); + + std::cout << std::endl << "bool: "; + testType(val); + + std::cout << std::endl << "unsigned char: "; + testType(val); + + std::cout << std::endl << "unsigned int: "; + testType(val); + + std::cout << std::endl << "unsigned long: "; + testType(val); + + std::cout << std::endl << "unsigned long long: "; + testType(val); + + std::cout << std::endl << "unsigned short: "; + testType(val); + + std::cout << std::endl << "float: "; + testType(val); + + std::cout << std::endl << "double: "; + testType(val); + + std::cout << std::endl << "off_t: "; + testType(val); + + std::cout << std::endl; + + return 0; +} diff --git a/modules/c++/str/tests/VersionTest.cpp b/modules/c++/str/tests/VersionTest.cpp new file mode 100644 index 000000000..6df707023 --- /dev/null +++ b/modules/c++/str/tests/VersionTest.cpp @@ -0,0 +1,50 @@ +/* ========================================================================= + * This file is part of str-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2011, General Dynamics - Advanced Information Systems + * + * str-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include +#include + +#if defined(TEST_FUNTOR) +# define FORMAT_FUNC (std::string)str::Format +#else +# define FORMAT_FUNC str::format +#endif + +int main() +{ + std::cout << FORMAT_FUNC("Your version of str is %d.%d.%d\n", + STR_MAJOR_VERSION, STR_MINOR_VERSION, STR_MICRO_VERSION); + std::cout << "Specialization for string test..." << std::endl; + std::string ok("This test passes"); + std::cout << str::toType(ok) << std::endl; + + std::cout << "Testing the trim function..." << std::endl; + std::string s = " test "; + std::cout << "'" << s << "', length: " << s.length() << std::endl; + str::trim(s); + std::cout << "'" << s << "', length: " << s.length() << std::endl; + str::upper(s); + std::cout << "Upper: " << s << std::endl; + str::lower(s); + std::cout << "Lower: " << s << std::endl; + return 0; +} diff --git a/modules/c++/str/unittests/test_base_convert.cpp b/modules/c++/str/unittests/test_base_convert.cpp new file mode 100644 index 000000000..68554ed9f --- /dev/null +++ b/modules/c++/str/unittests/test_base_convert.cpp @@ -0,0 +1,49 @@ +/* ========================================================================= + * This file is part of str-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * str-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include +#include "TestCase.h" + +TEST_CASE(testConvert) +{ + TEST_ASSERT_EQ(str::toType("0x3BC7", 16), (long long) 0x3BC7); + TEST_ASSERT_EQ(str::toType("1101", 2), (long long) 13); + TEST_ASSERT_EQ(str::toType("231", 5), (long long) 66); + TEST_ASSERT_EQ(str::toType("0xFFFFFFFFFFFFFFFF", 16), + (unsigned long long) 0xFFFFFFFFFFFFFFFF); + TEST_ASSERT_EQ(str::toType("-10", 10), + (unsigned long long) -10); + TEST_ASSERT_EQ(str::toType("13", 4), (short) 7); +} + +TEST_CASE(testBadConvert) +{ + TEST_EXCEPTION(str::toType("Not a number", 10)); + TEST_EXCEPTION(str::toType("0xFFFFFFFFFFFFFFFF", 16)); + TEST_EXCEPTION(str::toType("0xFFFFF", 16)); +} + +int main(int argc, char* argv[]) +{ + TEST_CHECK(testConvert); + TEST_CHECK(testBadConvert); +} diff --git a/modules/c++/str/unittests/test_str.cpp b/modules/c++/str/unittests/test_str.cpp new file mode 100644 index 000000000..a7981475c --- /dev/null +++ b/modules/c++/str/unittests/test_str.cpp @@ -0,0 +1,177 @@ +/* ========================================================================= + * This file is part of str-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * str-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include +#include "TestCase.h" + +TEST_CASE(testTrim) +{ + std::string s = " test "; + str::trim( s); + TEST_ASSERT_EQ(s, "test"); +} + +TEST_CASE(testUpper) +{ + std::string s = "test-something1"; + str::upper( s); + TEST_ASSERT_EQ(s, "TEST-SOMETHING1"); +} + +TEST_CASE(testLower) +{ + std::string s = "TEST1"; + str::lower( s); + TEST_ASSERT_EQ(s, "test1"); +} + +TEST_CASE(testReplace) +{ + std::string s = "helo world"; + str::replace(s, "l", "ll"); + TEST_ASSERT_EQ(s, "hello world"); +} + +TEST_CASE(testReplaceAllInfinite) +{ + std::string s = "helo hello"; + str::replaceAll(s, "l", "ll"); + TEST_ASSERT_EQ(s, "hello hellllo"); +} + +TEST_CASE(testReplaceAllRecurse) +{ + std::string s = "Mississippi"; + str::replaceAll(s, "i", " "); + TEST_ASSERT_EQ(s, "M ss ss pp "); +} + +TEST_CASE(testContains) +{ + std::string s = "Mississippi"; + TEST_ASSERT_TRUE(str::contains(s, "ssiss")); +} + +TEST_CASE(testNotContains) +{ + std::string s = "Mississippi"; + TEST_ASSERT_FALSE(str::contains(s, "miss")); +} + +TEST_CASE(testSplit) +{ + std::string s = "space delimited values are the best!"; + std::vector parts = str::split(s, " "); + TEST_ASSERT_EQ(parts.size(), 6); + parts = str::split(s, " ", 3); + TEST_ASSERT_EQ(parts.size(), 3); + TEST_ASSERT_EQ(parts[2], "values are the best!"); +} + +TEST_CASE(testIsAlpha) +{ + TEST_ASSERT(str::isAlpha("abcdefghijklmnopqrstuvwxyz")); + TEST_ASSERT_FALSE(str::isAlpha("abc123")); + TEST_ASSERT_FALSE(str::isAlpha("abcs with spaces")); +} +TEST_CASE(testIsAlphaSpace) +{ + TEST_ASSERT(str::isAlphaSpace("abcdefghijklmnopqrstuvwxyz")); + TEST_ASSERT_FALSE(str::isAlphaSpace("abc123")); + TEST_ASSERT(str::isAlphaSpace("abcs with spaces")); +} +TEST_CASE(testIsNumeric) +{ + TEST_ASSERT_FALSE(str::isNumeric("abcdefghijklmnopqrstuvwxyz")); + TEST_ASSERT_FALSE(str::isNumeric("abc123")); + TEST_ASSERT_FALSE(str::isNumeric("abcs with spaces")); + TEST_ASSERT(str::isNumeric("42")); +} +TEST_CASE(testIsNumericSpace) +{ + TEST_ASSERT_FALSE(str::isNumericSpace("lotto47")); + TEST_ASSERT(str::isNumericSpace("42")); + TEST_ASSERT(str::isNumericSpace("42 15 23 5 12")); +} +TEST_CASE(testIsAlphanumeric) +{ + TEST_ASSERT(str::isAlphanumeric("lotto47")); + TEST_ASSERT(str::isAlphanumeric("42")); + TEST_ASSERT_FALSE(str::isAlphanumeric("42 15 23 5 12")); + TEST_ASSERT(str::isAlphanumeric("justtext")); +} +TEST_CASE(testIsWhitespace) +{ + TEST_ASSERT_FALSE(str::isWhitespace("lotto47")); + TEST_ASSERT(str::isWhitespace("")); + TEST_ASSERT(str::isWhitespace(" ")); + TEST_ASSERT(str::isWhitespace(" ")); + TEST_ASSERT(str::isWhitespace("\t")); + TEST_ASSERT(str::isWhitespace("\t \n")); +} +TEST_CASE(testContainsOnly) +{ + TEST_ASSERT(str::containsOnly("abc", "abcdefghijklmnopqrstuvwxyz")); + TEST_ASSERT_FALSE(str::containsOnly("abc!", "abcdefghijklmnopqrstuvwxyz")); + TEST_ASSERT(str::containsOnly("some-cool-id", "-abcdefghijklmnopqrstuvwxyz")); + TEST_ASSERT(str::containsOnly("\n\r\t ", " \t\n\r0123456789")); + TEST_ASSERT(str::containsOnly("1-2-3", " \t\n\r0123456789-")); +} +TEST_CASE(testRoundDouble) +{ + double eps = std::numeric_limits::epsilon(); + double numerator = 10005.0; + double denom = 10007.0; + double v = numerator / denom; + std::string s = str::toString(v); + std::cout << s << std::endl; + + double nv = str::toType(s); + TEST_ASSERT_ALMOST_EQ_EPS(nv, v, eps); + nv *= denom; + TEST_ASSERT_ALMOST_EQ_EPS(nv, numerator, eps); + std::cout << nv << std::endl; + std::cout << (nv - (int)nv) << std::endl; + std::cout << std::numeric_limits::epsilon() << std::endl; + TEST_ASSERT_EQ((int)std::ceil(nv), (int)numerator); +} + +int main(int argc, char* argv[]) +{ + TEST_CHECK( testTrim); + TEST_CHECK( testUpper); + TEST_CHECK( testLower); + TEST_CHECK( testReplace); + TEST_CHECK( testReplaceAllInfinite); + TEST_CHECK( testReplaceAllRecurse); + TEST_CHECK( testContains); + TEST_CHECK( testNotContains); + TEST_CHECK( testSplit); + TEST_CHECK( testIsAlpha); + TEST_CHECK( testIsAlphaSpace); + TEST_CHECK( testIsNumeric); + TEST_CHECK( testIsNumericSpace); + TEST_CHECK( testIsAlphanumeric); + TEST_CHECK( testIsWhitespace); + TEST_CHECK( testContainsOnly); + TEST_CHECK( testRoundDouble); +} diff --git a/modules/c++/str/wscript b/modules/c++/str/wscript new file mode 100644 index 000000000..5e281f0bf --- /dev/null +++ b/modules/c++/str/wscript @@ -0,0 +1,10 @@ +NAME = 'str' +MAINTAINER = 'jmrandol@users.sourceforge.net' +VERSION = '1.0' +MODULE_DEPS = 'except' +UNITTEST_DEPS = 'sys' + +options = configure = distclean = lambda p: None + +def build(bld): + bld.module(**globals()) diff --git a/modules/c++/sys/include/import/sys.h b/modules/c++/sys/include/import/sys.h new file mode 100644 index 000000000..1fccff0f8 --- /dev/null +++ b/modules/c++/sys/include/import/sys.h @@ -0,0 +1,64 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __IMPORT_SYS_H__ +#define __IMPORT_SYS_H__ + +#include "sys/AtomicCounter.h" +#include "sys/ConditionVar.h" +#include "sys/Conf.h" +#include "sys/DateTime.h" +#include "sys/Dbg.h" +#include "sys/DirectoryEntry.h" +#include "sys/DLL.h" +#include "sys/Err.h" +#include "sys/Exec.h" +#include "sys/File.h" +#include "sys/FileFinder.h" +#include "sys/LocalDateTime.h" +#include "sys/Mutex.h" +#include "sys/OS.h" +#include "sys/Path.h" +#include "sys/ReadWriteMutex.h" +#include "sys/Runnable.h" +#include "sys/Semaphore.h" +#include "sys/StopWatch.h" +#include "sys/SystemException.h" +#include "sys/TimeStamp.h" +#include "sys/Thread.h" +#include "sys/UTCDateTime.h" +//#include "sys/Process.h" + +/*! + +\file sys.h + +The sys library servers the purpose of creating a common, system-indepenent +interface layer for cross-platform applications. It currently supports +UNIX and Windows, and provides interfaces for sockets, threads, +synchronization, conditions, time and operating system-specific function calls. + +*/ + +#endif + diff --git a/modules/c++/sys/include/sys/AbstractOS.h b/modules/c++/sys/include/sys/AbstractOS.h new file mode 100644 index 000000000..9f3c3f2ce --- /dev/null +++ b/modules/c++/sys/include/sys/AbstractOS.h @@ -0,0 +1,234 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __SYS_ABSTRACT_OS_H__ +#define __SYS_ABSTRACT_OS_H__ + +#include +#include +#include "sys/Conf.h" +#include "sys/FileFinder.h" +#include "sys/SystemException.h" +#include "str/Tokenizer.h" + +/*! + * \file + * \brief This class is the interface for an OS Abstraction layer. + * + * The class contains the interface for the abstraction layer for + * an operating system independent layer. + * + */ +namespace sys +{ +/*! + * \class AbstractOS + * \brief Interface for system independent function calls + * + * The AbstractOS class defines the base for a system + * independent layer of function calls. + */ +class AbstractOS +{ +public: + AbstractOS(); + + virtual ~AbstractOS(); + + /*! + * Get the name of the platform this was compiled for + * This is done by retrieving the 'target' variable + * in configure and forcing it to be defined for sys + * + * \return The name of the platform. + * + */ + virtual std::string getPlatformName() const = 0; + + /*! + * Get the name of the host machine + * + * \return the name of the host machine + */ + virtual std::string getNodeName() const = 0; + + /*! + * Get the path delimiter for this operating system. + * For windows, this will be two slashes \\ + * For unix it will be one slash / + * \return The path delimiter + */ + virtual const char* getDelimiter() const = 0; + + /*! + * Search recursively for some fragment with the directory. + * This will return both directories and files with the + * fragment, unless the user specifies the extension. + * + * \param elementsFound All retrieved enumerations + * \param fragment The fragment to search for + * \param extension extensions should only be used for files + * \param pathList The path list (colon delimited) + */ + std::vector + search(const std::vector& searchPaths, + const std::string& fragment = "", + const std::string& extension = "", + bool recursive = true) const; + + /*! + * Does this path exist? + * \param path The path to check for + * \return True if it does, false otherwise + */ + virtual bool exists(const std::string& path) const = 0; + + /*! + * Remove file with this path name + * \return True upon success, false if failure + */ + virtual bool remove(const std::string& path, bool recursive = true) const; + + /*! + * Move file with this path name to the newPath + * \return True upon success, false if failure + */ + virtual bool move(const std::string& path, + const std::string& newPath) const = 0; + + /*! + * Does this path resolve to a file? + * \param path The path + * \return True if it does, false if not + */ + virtual bool isFile(const std::string& path) const = 0; + + /*! + * Does this path resolve to a directory? + * \param path The path + * \return True if it does, false if not + */ + virtual bool isDirectory(const std::string& path) const = 0; + + /*! + * Create a directory with for the path specified + * \param path The path to create + * \return True on success, false on failure (since + * you may only create if no such exists) + */ + virtual bool makeDirectory(const std::string& path) const = 0; + + /*! + * Retrieve the current working directory. + * \return The current working directory + */ + virtual std::string getCurrentWorkingDirectory() const = 0; + + /*! + * Change the current working directory. + * \return true if the directory was changed, otherwise false. + */ + virtual bool changeDirectory(const std::string& path) const = 0; + + /*! + * Get a suitable temporary file name + * \return The file name + * + */ + virtual std::string getTempName(const std::string& path = "", + const std::string& prefix = "") const = 0; + + /*! + * Return the size in bytes of a file + * \return The file size + */ + virtual sys::Off_T getSize(const std::string& path) const = 0; + + /*! + * Return the last modified time of a file + * \return The last modified time, in millis + */ + virtual sys::Off_T getLastModifiedTime(const std::string& path) const = 0; + + /*! + * This is a system independent sleep function. + * Be careful using timing calls with threads + * \param milliseconds The params + */ + virtual void millisleep(int milliseconds) const = 0; + + /*! + * Get an environment variable + */ + virtual std::string operator[](const std::string& s) const = 0; + + /*! + * Get an environment variable + */ + virtual std::string getEnv(const std::string& s) const = 0; + + /*! + * Set an environment variable + */ + virtual void setEnv(const std::string& var, + const std::string& val, + bool overwrite) = 0; + + virtual Pid_T getProcessId() const = 0; + + virtual std::string getDSOSuffix() const = 0; + + virtual size_t getNumCPUs() const = 0; + +protected: + /*! + * Remove file with this pathname + * \return True upon success, false if failure + */ + virtual bool removeFile(const std::string& pathname) const = 0; + + /*! + * Remove directory with this pathname + * \return True upon success, false if failure + */ + virtual bool removeDirectory(const std::string& pathname) const = 0; +}; + +class AbstractDirectory +{ +public: + AbstractDirectory() + { + } + virtual ~AbstractDirectory() + { + } + virtual void close() = 0; + virtual std::string findFirstFile(const std::string& dir) = 0; + virtual std::string findNextFile() = 0; + +}; + +} + +#endif + diff --git a/modules/c++/sys/include/sys/AtomicCounter.h b/modules/c++/sys/include/sys/AtomicCounter.h new file mode 100644 index 000000000..1c8fdf2f1 --- /dev/null +++ b/modules/c++/sys/include/sys/AtomicCounter.h @@ -0,0 +1,157 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __SYS_ATOMIC_COUNTER_H__ +#define __SYS_ATOMIC_COUNTER_H__ + +#if defined( __GNUC__ ) && ( defined( __i386__ ) || defined( __x86_64__ ) ) +#include +#elif defined(WIN32) +#include +#elif defined(__sun) && defined(HAVE_ATOMIC_H) +// atomic.h is available in Solaris 10+ +// TODO: For Solaris 9 and older, we currently use the mutex implementation +// http://blogs.oracle.com/d/entry/atomic_operations +// provides a snippet of assembly code for atomic incrementing in +// Solaris 9 - this would be a starting point if a faster implementation +// is needed +#include +#else +// Bummer - need to fall back on a slow mutex implementation +#include +#endif + +namespace sys +{ +/*! + * \class AtomicCounter + * \brief This class provides atomic incrementing, decrementing, and setting + * of an unsigned integer. All operations are thread-safe. + * + * TODO: Currently, we use the ValueType typedef for whatever the underlying + * integer type is. Should we instead provide implementations that are + * explicitly for 32 bit and 64 bit integers? For Solaris and Windows, + * there are equivalent instructions so this would be simple. For X86, + * would need to research the assembly instructions to find the + * equivalent 64-bit instruction. + * + * TODO: Provide other operations such as getThenSet() and compareThenSet(). + */ +class AtomicCounter +{ +public: + typedef AtomicCounterImpl::ValueType ValueType; + + //! Constructor + AtomicCounter(ValueType initialValue = 0) : + mImpl(initialValue) + { + } + + /*! + * Increment the value + * \return The value PRIOR to incrementing + */ + ValueType getThenIncrement() + { + return mImpl.getThenIncrement(); + } + + ValueType operator++(int ) + { + return getThenIncrement(); + } + + /*! + * Increment the value + * \return The value AFTER incrementing + */ + ValueType incrementThenGet() + { + return (getThenIncrement() + 1); + } + + ValueType operator++() + { + return incrementThenGet(); + } + + //! Increment the value + void increment() + { + getThenIncrement(); + } + + /*! + * Decrement the value + * \return The value PRIOR to decrementing + */ + ValueType getThenDecrement() + { + return mImpl.getThenDecrement(); + } + + ValueType operator--(int ) + { + return getThenDecrement(); + } + + /*! + * Decrement the value + * \return The value AFTER decrementing + */ + ValueType decrementThenGet() + { + return (getThenDecrement() - 1); + } + + ValueType operator--() + { + return decrementThenGet(); + } + + //! Decrement the value + void decrement() + { + getThenDecrement(); + } + + /*! + * Get the current value + * \return The current value + */ + ValueType get() const + { + return mImpl.get(); + } + +private: + // Noncopyable + AtomicCounter(const AtomicCounter& ); + const AtomicCounter& operator=(const AtomicCounter& ); + +private: + AtomicCounterImpl mImpl; +}; +} + +#endif diff --git a/modules/c++/sys/include/sys/AtomicCounterMutex.h b/modules/c++/sys/include/sys/AtomicCounterMutex.h new file mode 100644 index 000000000..a331d7316 --- /dev/null +++ b/modules/c++/sys/include/sys/AtomicCounterMutex.h @@ -0,0 +1,87 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __SYS_ATOMIC_COUNTER_MUTEX_H__ +#define __SYS_ATOMIC_COUNTER_MUTEX_H__ + +#include + +namespace sys +{ +class AtomicCounterImpl +{ +public: + typedef size_t ValueType; + + explicit + AtomicCounterImpl(ValueType initialValue) : + mValue(initialValue) + { + } + + ValueType getThenIncrement() + { + ValueType value; + + mMutex.lock(); + value = mValue; + ++mValue; + mMutex.unlock(); + + return value; + } + + ValueType getThenDecrement() + { + ValueType value; + + mMutex.lock(); + value = mValue; + --mValue; + mMutex.unlock(); + + return value; + } + + ValueType get() const + { + ValueType value; + + mMutex.lock(); + value = mValue; + mMutex.unlock(); + + return value; + } + +private: + // Noncopyable + AtomicCounterImpl(const AtomicCounterImpl& ); + const AtomicCounterImpl& operator=(const AtomicCounterImpl& ); + +private: + ValueType mValue; + mutable Mutex mMutex; +}; +} + +#endif diff --git a/modules/c++/sys/include/sys/AtomicCounterSolaris.h b/modules/c++/sys/include/sys/AtomicCounterSolaris.h new file mode 100644 index 000000000..5623942f1 --- /dev/null +++ b/modules/c++/sys/include/sys/AtomicCounterSolaris.h @@ -0,0 +1,69 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __SYS_ATOMIC_COUNTER_SOLARIS_H__ +#define __SYS_ATOMIC_COUNTER_SOLARIS_H__ + +#include + +#include + +namespace sys +{ +// Implemented from boost/smart_ptr/detail/atomic_count_solaris.hpp +class AtomicCounterImpl +{ +public: + typedef Uint32_T ValueType; + + explicit + AtomicCounterImpl(ValueType initialValue) : + mValue(initialValue) + { + } + + ValueType getThenIncrement() + { + return (atomic_inc_32_nv(&mValue) - 1); + } + + ValueType getThenDecrement() + { + return (atomic_dec_32_nv(&mValue) + 1); + } + + ValueType get() const + { + return static_cast(mValue); + } + +private: + // Noncopyable + AtomicCounterImpl(const AtomicCounterImpl& ); + const AtomicCounterImpl& operator=(const AtomicCounterImpl& ); + +private: + ValueType mValue; +}; +} + +#endif diff --git a/modules/c++/sys/include/sys/AtomicCounterWin32.h b/modules/c++/sys/include/sys/AtomicCounterWin32.h new file mode 100644 index 000000000..08e1a4daf --- /dev/null +++ b/modules/c++/sys/include/sys/AtomicCounterWin32.h @@ -0,0 +1,68 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __SYS_ATOMIC_COUNTER_WIN32_H__ +#define __SYS_ATOMIC_COUNTER_WIN32_H__ + +// In order to include windows.h with the appropriate stuff defined beforehand +#include + +namespace sys +{ +// Implemented from boost/smart_ptr/detail/atomic_count_win32.hpp +class AtomicCounterImpl +{ +public: + typedef long ValueType; + + explicit + AtomicCounterImpl(ValueType initialValue) : + mValue(initialValue) + { + } + + ValueType getThenIncrement() + { + return (InterlockedIncrement(&mValue) - 1); + } + + ValueType getThenDecrement() + { + return (InterlockedDecrement(&mValue) + 1); + } + + ValueType get() const + { + return static_cast(mValue); + } + +private: + // Noncopyable + AtomicCounterImpl(const AtomicCounterImpl& ); + const AtomicCounterImpl& operator=(const AtomicCounterImpl& ); + +private: + ValueType mValue; +}; +} + +#endif diff --git a/modules/c++/sys/include/sys/AtomicCounterX86.h b/modules/c++/sys/include/sys/AtomicCounterX86.h new file mode 100644 index 000000000..c1376a83e --- /dev/null +++ b/modules/c++/sys/include/sys/AtomicCounterX86.h @@ -0,0 +1,87 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __SYS_ATOMIC_COUNTER_X86_H__ +#define __SYS_ATOMIC_COUNTER_X86_H__ + +namespace sys +{ +// Implemented from boost/smart_ptr/detail/atomic_count_gcc_x86.hpp +class AtomicCounterImpl +{ +public: + typedef int ValueType; + + explicit + AtomicCounterImpl(ValueType initialValue) : + mValue(initialValue) + { + } + + ValueType getThenIncrement() + { + return atomicExchangeAndAdd(&mValue, 1); + } + + ValueType getThenDecrement() + { + return atomicExchangeAndAdd(&mValue, -1); + } + + ValueType get() const + { + return atomicExchangeAndAdd(&mValue, 0); + } + +private: + static + ValueType atomicExchangeAndAdd(ValueType* pw, ValueType dv) + { + // int r = *pw; + // *pw += dv; + // return r; + + int r; + + __asm__ __volatile__ + ( + "lock\n\t" + "xadd %1, %0": + "+m"( *pw ), "=r"( r ): // outputs (%0, %1) + "1"( dv ): // inputs (%2 == %1) + "memory", "cc" // clobbers + ); + + return r; + } + +private: + // Noncopyable + AtomicCounterImpl(const AtomicCounterImpl& ); + const AtomicCounterImpl& operator=(const AtomicCounterImpl& ); + +private: + mutable ValueType mValue; +}; +} + +#endif diff --git a/modules/c++/sys/include/sys/ConditionVar.h b/modules/c++/sys/include/sys/ConditionVar.h new file mode 100644 index 000000000..15460144d --- /dev/null +++ b/modules/c++/sys/include/sys/ConditionVar.h @@ -0,0 +1,71 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __SYS_CONDITION_VAR_H__ +#define __SYS_CONDITION_VAR_H__ + +# if defined(_REENTRANT) + +# if defined(USE_NSPR_THREADS) +# include "sys/ConditionVarNSPR.h" +namespace sys +{ +typedef ConditionVarNSPR ConditionVar; +} +// If they explicitly want posix +# elif defined(__POSIX) +# include "sys/ConditionVarPosix.h" +namespace sys +{ +typedef ConditionVarPosix ConditionVar; +} +# elif defined(WIN32) +# include "sys/ConditionVarWin32.h" +namespace sys +{ +typedef ConditionVarWin32 ConditionVar; +} +# elif defined(__sun) && !defined(__POSIX) +# include "sys/ConditionVarSolaris.h" +namespace sys +{ +typedef ConditionVarSolaris ConditionVar; +} +# elif defined(__sgi) && !defined(__POSIX) +# include "sys/ConditionVarIrix.h" +namespace sys +{ +typedef ConditionVarIrix ConditionVar; +} +# else +# include "sys/ConditionVarPosix.h" +namespace sys +{ +typedef ConditionVarPosix ConditionVar; +} +# endif // Which thread package? + +# endif // Are we reentrant? + +#endif // End of header + diff --git a/modules/c++/sys/include/sys/ConditionVarInterface.h b/modules/c++/sys/include/sys/ConditionVarInterface.h new file mode 100644 index 000000000..d8361618c --- /dev/null +++ b/modules/c++/sys/include/sys/ConditionVarInterface.h @@ -0,0 +1,128 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __SYS_CONDITION_VAR_INTERFACE_H__ +#define __SYS_CONDITION_VAR_INTERFACE_H__ + +#if defined(_REENTRANT) +#include +#include "sys/SystemException.h" +#include "sys/Mutex.h" +namespace sys +{ +/*! + * \class ConditionVarInterface + * \brief Interface for any condition variable implementation + * + * Provide the API for condition variables in this thread wrapper + */ + +class ConditionVarInterface +{ +public: + + /*! + * This constructor means that you are creating the lock + * that you will use inside of the condition variable. + * This means that we should delete this ourselves, + * so the mIsOwner flag is set to true. Its up to the derived + * class to implement this default constructor. Really, this + * option is only necessary for CASPR condition variables. It + * is not the recommended behavior but it may be useful. + */ + ConditionVarInterface() + {} + + /*! + * This constructor is the preferred method for creating a new + * condition variable. It shares a global lock, which must be + * deleted externally, by default. + * + * \param theLock This is an existing lock that you wish to + * use for synchronization purposes + * + * \param isOwner This defaults to false, which means that your + * condition variable is not responsible for the deletion of the + * mutex (in other words, you must delete the mutex explicitly. + * If you set this parameter to true, you may actually be sharing + * a lock, but this class will STILL delete it. + * + */ + ConditionVarInterface(Mutex *, bool = false) + {} + + //! Destructor + virtual ~ConditionVarInterface() + {} + + /*! + * Acquire the lock + */ + virtual void acquireLock() = 0; + + /*! + * Drop (release) the lock + */ + virtual void dropLock() = 0; + + /*! + * Wait for on a signal for a time interval. + * This should eventually have + * a class TimeInterval as the second argument, which takes + * any time interval as a right-hand-side + * \param timeout How long to wait. This is only temporarily + * a double + * \todo Create a TimeInterval class, and use it as parameter + * + * WARNING: The user is responsible for locking the mutex prior + * to using this method. There will be no check and on + * certain systems, undefined/unfavorable behavior may + * result. + */ + virtual void wait(double timeout) = 0; + + /*! + * Wait on a signal + * + * WARNING: The user is responsible for locking the mutex prior + * to using this method. There will be no check and on + * certain systems, undefined/unfavorable behavior may + * result. + */ + virtual void wait() = 0; + + /*! + * Signal (notify) + */ + virtual void signal() = 0; + + /*! + * Broadcast (notify all) + */ + virtual void broadcast() = 0; + +}; + +} +#endif +#endif diff --git a/modules/c++/sys/include/sys/ConditionVarIrix.h b/modules/c++/sys/include/sys/ConditionVarIrix.h new file mode 100644 index 000000000..74bd2c6f7 --- /dev/null +++ b/modules/c++/sys/include/sys/ConditionVarIrix.h @@ -0,0 +1,144 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __SYS_CONDITION_VAR_IRIX_H__ +#define __SYS_CONDITION_VAR_IRIX_H__ + +#if defined(__sgi) && defined(_REENTRANT) && !defined(__POSIX) + +#include +#include "sys/SyncFactoryIrix.h" +#include "sys/ConditionVarInterface.h" +#include "sys/MutexIrix.h" + + +namespace sys +{ +/*! + * \class ConditionVarIrix + * \brief The Netscape Portable Runtime condition variable + * implementation + * + * Class using PRCondVar* to implement a condition variable + */ +class ConditionVarIrix : public ConditionVarInterface +{ +public: + + /*! + * This constructor means that you are creating the lock + * that you will use inside of the condition variable. + * The base class destructor will remove this mutex when we + * are destroyed. + */ + ConditionVarIrix(); + + /*! + * This is the sharing constructor. In synchronized buffers, etc., + * it is often desirable to share the lock that you use. Here, + * we implement such a means. + * + * \param theLock This is an existing lock that you wish to + * use for synchronization purposes + * + * \param isOwner This defaults to false, which means that your + * condition variable is not responsible for the deletion of the + * mutex (in other words, you must delete the mutex explicitly. + * If you set this parameter to true, you may actually be sharing + * a lock, but this class will STILL delete it. + * + */ + ConditionVarIrix(MutexIrix *theLock, bool isOwner = false); + + /*! + * Destroy the native CV + */ + virtual ~ConditionVarIrix(); + + /*! + * Acquire the lock + */ + virtual void acquireLock(); + + /*! + * Drop (release) the lock + */ + virtual void dropLock(); + + /*! + * Signal a condition + */ + virtual void signal(); + + /*! + * Wait on a condition + * + * WARNING: The user is responsible for locking the mutex prior + * to using this method. There will be no check and on + * certain systems, undefined/unfavorable behavior may + * result. + */ + virtual void wait(); + + /*! + * Timed wait on a condition + * \param seconds The number of seconds to wait as a fraction + * + * WARNING: The user is responsible for locking the mutex prior + * to using this method. There will be no check and on + * certain systems, undefined/unfavorable behavior may + * result. + */ + virtual void wait(double seconds); + + + /*! + * Broadcast operation + */ + virtual void broadcast(); + + /*! + * Returns the native type. + */ + std::vector& getNative(); + + /*! + * Return the type name. This function is essentially free, + * because it is static RTTI. + */ + const char* getNativeType() const + { + return typeid(mNative).name(); + } + +private: + // This is set if we own the mutex, to make sure it gets deleted. + std::auto_ptr mMutexOwned; + MutexIrix *mMutex; + std::vector mNative; +}; + +} + +# endif +#endif diff --git a/modules/c++/sys/include/sys/ConditionVarNSPR.h b/modules/c++/sys/include/sys/ConditionVarNSPR.h new file mode 100644 index 000000000..ea288bcc7 --- /dev/null +++ b/modules/c++/sys/include/sys/ConditionVarNSPR.h @@ -0,0 +1,144 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __SYS_CONDITION_VAR_NSPR_H__ +#define __SYS_CONDITION_VAR_NSPR_H__ + +# if defined(USE_NSPR_THREADS) + +#include "sys/ConditionVarInterface.h" +#include "sys/MutexNSPR.h" +#include +#include +#include + +namespace sys +{ +/*! + * \class ConditionVarNSPR + * \brief The Netscape Portable Runtime condition variable + * implementation + * + * Class using PRCondVar* to implement a condition variable + */ +class ConditionVarNSPR : public ConditionVarInterface +{ +public: + + /*! + * This constructor means that you are creating the lock + * that you will use inside of the condition variable. + * The base class destructor will remove this mutex when we + * are destroyed. + */ + ConditionVarNSPR(); + + /*! + * This is the sharing constructor. In synchronized buffers, etc., + * it is often desirable to share the lock that you use. Here, + * we implement such a means. + * + * \param theLock This is an existing lock that you wish to + * use for synchronization purposes + * + * \param isOwner This defaults to false, which means that your + * condition variable is not responsible for the deletion of the + * mutex (in other words, you must delete the mutex explicitly. + * If you set this parameter to true, you may actually be sharing + * a lock, but this class will STILL delete it. + * + */ + ConditionVarNSPR(MutexNSPR *theLock, bool isOwner = false); + + /*! + * Destroy the native CV + */ + virtual ~ConditionVarNSPR(); + + /*! + * Acquire the lock + */ + virtual void acquireLock(); + + /*! + * Drop (release) the lock + */ + virtual void dropLock(); + + /*! + * Signal a condition + */ + virtual void signal(); + + /*! + * Wait on a condition + * + * WARNING: The user is responsible for locking the mutex prior + * to using this method. There will be no check and on + * certain systems, undefined/unfavorable behavior may + * result. + */ + virtual void wait(); + + /*! + * Timed wait on a condition + * \param seconds The number of seconds to wait as a fraction + * + * WARNING: The user is responsible for locking the mutex prior + * to using this method. There will be no check and on + * certain systems, undefined/unfavorable behavior may + * result. + */ + virtual void wait(double seconds); + + /*! + * Broadcast operation + */ + virtual void broadcast(); + + /*! + * Returns the native type. + */ + PRCondVar*& getNative(); + + /*! + * Return the type name. This function is essentially free, + * because it is static RTTI. + */ + const char* getNativeType() const + { + return typeid(mNative).name(); + } + +private: + // This is set if we own the mutex, to make sure it gets deleted. + std::auto_ptr mMutexOwned; + MutexNSPR *mMutex; + PRCondVar *mNative; +}; + + +} + +# endif +#endif diff --git a/modules/c++/sys/include/sys/ConditionVarPosix.h b/modules/c++/sys/include/sys/ConditionVarPosix.h new file mode 100644 index 000000000..02dd47c39 --- /dev/null +++ b/modules/c++/sys/include/sys/ConditionVarPosix.h @@ -0,0 +1,121 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __SYS_THREAD_PTHREAD_CONDITION_VARIABLE_H__ +#define __SYS_THREAD_PTHREAD_CONDITION_VARIABLE_H__ + +#if defined(__POSIX) && defined(_REENTRANT) + +#include "sys/MutexPosix.h" +#include "sys/ConditionVarInterface.h" +#include + +namespace sys +{ + +/*! + * \class ConditionVarPosix + * \brief Implementation for a pthread condition variable + * + * This class is the wrapper implementation for a pthread_cond_t + * (Pthread condition variable) + */ +class ConditionVarPosix : public ConditionVarInterface +{ +public: + + ConditionVarPosix(); + + //! Constructor + ConditionVarPosix(MutexPosix* theLock, bool isOwner = false); + + //! Destructor + virtual ~ConditionVarPosix(); + + /*! + * Acquire the lock + */ + virtual void acquireLock(); + + /*! + * Drop (release) the lock + */ + virtual void dropLock(); + + /*! + * Signal using pthread_cond_signal + */ + virtual void signal(); + + /*! + * Wait using pthread_cond_wait + * + * WARNING: The user is responsible for locking the mutex prior + * to using this method. There will be no check and on + * certain systems, undefined/unfavorable behavior may + * result. + */ + virtual void wait(); + + /*! + * Wait using pthread_cond_timed_wait. I kept this and the above + * function separate only to be explicit. + * \param seconds Fraction of a second to wait. + * \todo Want a TimeInterval + * + * WARNING: The user is responsible for locking the mutex prior + * to using this method. There will be no check and on + * certain systems, undefined/unfavorable behavior may + * result. + */ + virtual void wait(double seconds); + + /*! + * Broadcast (notify all) + */ + virtual void broadcast(); + + /*! + * Returns the native type. + */ + pthread_cond_t& getNative(); + + /*! + * Return the type name. This function is essentially free, + * because it is static RTTI. + */ + const char* getNativeType() const + { + return typeid(mNative).name(); + } + +private: + // This is set if we own the mutex, to make sure it gets deleted. + std::auto_ptr mMutexOwned; + MutexPosix *mMutex; + pthread_cond_t mNative; +}; +} + +#endif +#endif diff --git a/modules/c++/sys/include/sys/ConditionVarSolaris.h b/modules/c++/sys/include/sys/ConditionVarSolaris.h new file mode 100644 index 000000000..61034fd5d --- /dev/null +++ b/modules/c++/sys/include/sys/ConditionVarSolaris.h @@ -0,0 +1,119 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __SYS_THREAD_SOLARIS_CONDITION_VARIABLE_H__ +#define __SYS_THREAD_SOLARIS_CONDITION_VARIABLE_H__ + +#if defined(__sun) && defined(_REENTRANT) && !defined(__POSIX) +#include +#include +#include "sys/ConditionVarInterface.h" +#include "sys/MutexSolaris.h" +namespace sys +{ +/*! + * \class ConditionVarSolaris + * \brief Implementation for a solaris thread condition variable + * + * This class is the wrapper implementation for a solaris cond_t + * (Solaris condition variable) + */ +class ConditionVarSolaris : public sys::ConditionVarInterface +{ +public: + ConditionVarSolaris(); + + //! Constructor + ConditionVarSolaris(MutexSolaris* theLock, bool isOwner = false); + + //! Destructor + virtual ~ConditionVarSolaris(); + + /*! + * Acquire the lock + */ + virtual void acquireLock(); + + /*! + * Drop (release) the lock + */ + virtual void dropLock(); + + /*! + * Signal using solaris cond_signal + */ + virtual void signal(); + + /*! + * Wait using cond_wait + * + * WARNING: The user is responsible for locking the mutex prior + * to using this method. There will be no check and on + * certain systems, undefined/unfavorable behavior may + * result. + */ + virtual void wait(); + + /*! + * Wait using cond_timed_wait. I kept this and the above + * function separate only to be explicit. + * \param seconds Fraction of a second to wait. Want a TimeInterval + * \todo Make a parameter initializer that does wait() + * + * WARNING: The user is responsible for locking the mutex prior + * to using this method. There will be no check and on + * certain systems, undefined/unfavorable behavior may + * result. + */ + virtual void wait(double seconds); + + /*! + * Broadcast (notify all) + */ + virtual void broadcast(); + + /*! + * Returns the native type. + */ + cond_t& getNative(); + + /*! + * Return the type name. This function is essentially free, + * because it is static RTTI. + */ + const char* getNativeType() const + { + return typeid(mNative).name(); + } + +private: + // This is set if we own the mutex, to make sure it gets deleted. + std::auto_ptr mMutexOwned; + MutexSolaris *mMutex; + cond_t mNative; +}; + +} + +#endif +#endif diff --git a/modules/c++/sys/include/sys/ConditionVarWin32.h b/modules/c++/sys/include/sys/ConditionVarWin32.h new file mode 100644 index 000000000..e7a2d3f84 --- /dev/null +++ b/modules/c++/sys/include/sys/ConditionVarWin32.h @@ -0,0 +1,157 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __SYS_WIN32_CONDITION_VARIABLE_H__ +#define __SYS_WIN32_CONDITION_VARIABLE_H__ + +#if defined(WIN32) && defined(_REENTRANT) +#if !defined(USE_NSPR_THREADS) && !defined(__POSIX) + +#include "sys/ConditionVarInterface.h" +#include "sys/MutexWin32.h" + + +namespace sys +{ +/// @note This implementation is based on section 3.4 of the +/// "Strategies for Implementing POSIX Condition Variables on Win32" +/// article at www.cse.wustl.edu/~schmidt/win32-cv-1.html. +/// This is the ACE framework implementation. +class ConditionVarDataWin32 +{ +public: + ConditionVarDataWin32(); + + ~ConditionVarDataWin32(); + + void wait(HANDLE externalMutex); + + bool wait(HANDLE externalMutex, double timeout); + + void signal(); + + void broadcast(); + +private: + void waitImpl(HANDLE externalMutex); + +private: + // # of waiting threads + size_t mNumWaiters; + CRITICAL_SECTION mNumWaitersCS; + + // Semaphore used to queue up threads waiting for the condition to + // become signaled + HANDLE mSemaphore; + + // Auto-reset event used by the broadcast/signal thread to wait for + // all the waiting thread(s) to wake up and be released from the + // semaphore + HANDLE mWaitersAreDone; + + // Keep track of whether we were broadcasting or signaling. This + // allows us to optimize the code if we're just signaling. + bool mWasBroadcast; +}; + +class ConditionVarWin32 : public ConditionVarInterface + +{ +public: + + ConditionVarWin32(); + + ConditionVarWin32(MutexWin32 *theLock, bool isOwner = false); + + virtual ~ConditionVarWin32() + {} + + /*! + * Acquire the lock + */ + virtual void acquireLock(); + + /*! + * Drop (release) the lock + */ + virtual void dropLock(); + + /*! + * Signal using pthread_cond_signal + */ + virtual void signal(); + + /*! + * Wait using pthread_cond_wait + * + * WARNING: The user is responsible for locking the mutex prior + * to using this method. There will be no check and on + * certain systems, undefined/unfavorable behavior may + * result. + */ + virtual void wait(); + + /*! + * Wait using pthread_cond_timed_wait. I kept this and the above + * function separate only to be explicit. + * \param seconds Fraction of a second to wait. + * \todo Want a TimeInterval + * + * WARNING: The user is responsible for locking the mutex prior + * to using this method. There will be no check and on + * certain systems, undefined/unfavorable behavior may + * result. + */ + virtual void wait(double seconds); + + /*! + * Broadcast (notify all) + */ + virtual void broadcast(); + + /*! + * Returns the native type. + */ + ConditionVarDataWin32& getNative(); + + /*! + * Return the type name. This function is essentially free, + * because it is static RTTI. + */ + const char* getNativeType() const + { + return typeid(mNative).name(); + } + +private: + // This is set if we own the mutex, to make sure it gets deleted. + std::auto_ptr mMutexOwned; + MutexWin32 *mMutex; + ConditionVarDataWin32 mNative; +}; +} +#endif + +#endif + +#endif diff --git a/modules/c++/sys/include/sys/Conf.h b/modules/c++/sys/include/sys/Conf.h new file mode 100644 index 000000000..5cb442c23 --- /dev/null +++ b/modules/c++/sys/include/sys/Conf.h @@ -0,0 +1,392 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __SYS_CONF_H__ +#define __SYS_CONF_H__ + +#if defined (__APPLE_CC__) +# include +#endif + +#include +#include +#include + +#if defined(__sgi) || defined(__sgi__) +# include +# include +#else +# include +# include +#endif + +#include +#include "str/Format.h" +#include "sys/TimeStamp.h" + +#ifdef HAVE_CONFIG_H +# include "sys/config.h" +#endif + +/* Dance around the compiler to figure out */ +/* if we have access to function macro... */ + +/* If we have gnu -- Yes!! */ +#if defined(__GNUC__) + /* We get a really nice function macro */ +# define NativeLayer_func__ __PRETTY_FUNCTION__ +#elif defined(WIN32) && (_MSC_VER >= 1300) +# define NativeLayer_func__ __FUNCSIG__ +/* Otherwise, lets look for C99 compatibility */ +#elif defined (__STDC_VERSION__) + /* The above line may not be necessary but */ + /* Im not about to find out... */ + /* Check to see if the compiler is doing C99 */ +# if __STDC_VERSION__ < 199901 + /* If not, define an empty function signature */ +# define NativeLayer_func__ "" +# else + /* If so -- Yes!! Use it! */ +# define NativeLayer_func__ __func__ +# endif +#else +/* If STDC stuff isnt defined, that would be lame, but */ +/* lets make sure its still okay */ +# define NativeLayer_func__ "" +#endif + + + +#if defined(WIN32) || defined(_WIN32) +# include +# include +# include + + +namespace sys +{ + typedef char byte; + typedef unsigned char ubyte; + typedef HANDLE Handle_T; + typedef unsigned char Uint8_T; + typedef unsigned __int16 Uint16_T; + typedef unsigned __int32 Uint32_T; + typedef unsigned __int64 Uint64_T; + typedef signed char Int8_T; + typedef __int16 Int16_T; + typedef __int32 Int32_T; + typedef __int64 Int64_T; + typedef Int64_T Off_T; + typedef DWORD Pid_T; + typedef size_t Size_T; +# if SIZEOF_SIZE_T == 8 + typedef __int64 SSize_T; +# elif SIZEOF_SIZE_T == 4 + typedef __int32 SSize_T; +# else + #error SIZEOF_SIZE_T must be set at configure time +# endif +} +#else // !windows +# include +# if defined(__sgi) || defined(__sgi__) +# if defined(__GNUC__) +# ifdef _FIX_BROKEN_HEADERS + typedef __int64_t jid_t; +# endif +# endif +# endif +# if defined(__sun) || defined(__sun__) || defined(__sparc) || defined(__sparc) || defined(__sparc__) +# if !defined(__SunOS_5_6) && !defined(__SunOS_5_7) && !defined(__SunOS_5_8) && defined(__GNUC__) +# ifdef _FIX_BROKEN_HEADERS + typedef id_t projid_t; +# endif +# endif +# include +# endif +# include +# include +# include +# include +# include +# include +# include +# if defined(_USE_STDINT) +# include +# else +# include +# endif +//# include + +namespace sys +{ + + typedef char byte; + typedef unsigned char ubyte; + typedef uint8_t Uint8_T; + typedef uint16_t Uint16_T; + typedef uint32_t Uint32_T; + typedef uint64_t Uint64_T; + typedef size_t Size_T; + typedef ssize_t SSize_T; + typedef off_t Off_T; + typedef int8_t Int8_T; + typedef int16_t Int16_T; + typedef int32_t Int32_T; + typedef int64_t Int64_T; + typedef int Handle_T; + // Should we remove this? + typedef pid_t Pid_T; +} +#endif // *nix + +// For strerror +#include + +#ifdef signal // Apache defines this +# undef signal +#endif + +#include "except/Exception.h" + +#define FmtX str::format + +#define SYS_TIME sys::TimeStamp().local() + +#define SYS_FUNC NativeLayer_func__ + +#define Ctxt(MESSAGE) except::Context(__FILE__, __LINE__, SYS_FUNC, SYS_TIME, MESSAGE) + +namespace sys +{ + /*! + * Returns true if the system is big-endian, otherwise false. + * On Intel systems, we are usually small-endian, and on + * RISC architectures we are big-endian. + */ + bool isBigEndianSystem(); + + + /*! + * Swap bytes in-place. Note that a complex pixel + * is equivalent to two floats so elemSize and numElems + * must be adjusted accordingly. + * + * \param [inout] buffer to transform + * \param elemSize + * \param numElems + */ + inline void byteSwap(sys::byte *buffer, + const unsigned short elemSize, + const size_t numElems) + { + if (!buffer || elemSize < 2 || !numElems) + return; + + unsigned short half = elemSize >> 1; + size_t offset = 0, innerOff = 0, innerSwap = 0; + + for(size_t i = 0; i < numElems; ++i, offset += elemSize) + { + for(unsigned short j = 0; j < half; ++j) + { + innerOff = offset + j; + innerSwap = offset + elemSize - 1 - j; + + sys::byte tmp = buffer[innerOff]; + buffer[innerOff] = buffer[innerSwap]; + buffer[innerSwap] = tmp; + } + } + } + + /*! + * Function to swap one element irrespective of size. The inplace + * buffer function should be preferred. + * + * To specialize complex float, first include the complex library + * \code + #include + * \endcode + * + * Then put an overload in as specified below: + * \code + template std::complex byteSwap(std::complex val) + { + std::complex out(byteSwap(val.real()), + byteSwap(val.imag())); + return out; + } + * \endcode + * + */ + template T byteSwap(T val) + { + size_t size = sizeof(T); + T out; + + unsigned char* cOut = reinterpret_cast(&out); + unsigned char* cIn = reinterpret_cast(&val); + for (int i = 0, j = size - 1; i < j; ++i, --j) + { + cOut[i] = cIn[j]; + cOut[j] = cIn[i]; + } + return out; + } + + +#ifdef WIN32 + + /*! + * Method to create a block of memory on 16-byte boundary. + * This typically reduces the amount of moves that the + * OS has to do to get the data in the form that it needs + * to be in. Since this method is non-standard, we present + * OS-specific alternatives. + * + * \param sz The size (in bytes) of the buffer we wish to create + * \throw Exception if a bad allocation occurs + * \return a pointer to the data (this method never returns NULL) + */ + inline void* alignedAlloc(size_t sz) + { + void* p = _aligned_malloc(sz, 16); + if (!p) + throw except::Exception("_aligned_malloc: bad alloc"); + + return p; + } + + /*! + * Free memory that was allocated with alignedAlloc + * This method behaves like free + * + * \param p A pointer to the data allocated using alignedAlloc + */ + inline void alignedFree(void* p) + { + _aligned_free(p); + } +#elif defined(__POSIX) && !defined(__sun) + + /*! + * Method to create a block of memory on 16-byte boundary. + * This typically reduces the amount of moves that the + * OS has to do to get the data in the form that it needs + * to be in. Since this method is non-standard, we present + * OS-specific alternatives. + * + * \param sz The size (in bytes) of the buffer we wish to create + * \throw Exception if a bad allocation occurs + * \return a pointer to the data (this method never returns NULL) + */ + inline void* alignedAlloc(size_t sz) + { + void* p = NULL; + if (posix_memalign(&p, 16, sz) != 0) + throw except::Exception("posix_memalign: bad alloc"); + memset(p, 0, sz); + return p; + + } + + /*! + * Free memory that was allocated with alignedAlloc + * This method behaves like free + * + * \param p A pointer to the data allocated using alignedAlloc + */ + inline void alignedFree(void* p) + { + free(p); + } +#elif defined(__sun) + /*! + * Method to create a block of memory on 16-byte boundary. + * This typically reduces the amount of moves that the + * OS has to do to get the data in the form that it needs + * to be in. Since this method is non-standard, we present + * OS-specific alternatives. + * + * \param sz The size (in bytes) of the buffer we wish to create + * \throw Exception if a bad allocation occurs + * \return a pointer to the data (this method never returns NULL) + */ + inline void* alignedAlloc(size_t sz) + { + void* const p = memalign(16, sz); + if (p == NULL) + throw except::Exception("memalign: bad alloc"); + memset(p, 0, sz); + return p; + } + + /*! + * Free memory that was allocated with alignedAlloc + * This method behaves like free + * + * \param p A pointer to the data allocated using alignedAlloc + */ + inline void alignedFree(void* p) + { + free(p); + } +#else + + /*! + * Method to create a block of memory on 16-byte boundary. + * This typically reduces the amount of moves that the + * OS has to do to get the data in the form that it needs + * to be in. Since this method is non-standard, we present + * OS-specific alternatives. + * + * \param sz The size (in bytes) of the buffer we wish to create + * \throw Exception if a bad allocation occurs + * \return a pointer to the data (this method never returns NULL) + */ + inline void* alignedAlloc(size_t sz) + { + void* p = calloc(sz, 1); + if (p == NULL) + throw except::Exception("calloc: bad alloc"); + return p; + } + + /*! + * Free memory that was allocated with alignedAlloc + * This method behaves like free + * + * \param p A pointer to the data allocated using alignedAlloc + */ + inline void alignedFree(void* p) + { + free(p); + } +#endif + + +} + +#endif + diff --git a/modules/c++/sys/include/sys/DLL.h b/modules/c++/sys/include/sys/DLL.h new file mode 100644 index 000000000..a22a73505 --- /dev/null +++ b/modules/c++/sys/include/sys/DLL.h @@ -0,0 +1,211 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __SYS_DLL_H__ +#define __SYS_DLL_H__ + + +/*! + * \file DLL.h + * \brief Load DLL's using an object, in a system-independent fashion + * + * DLL's are often painful to use, especially in a cross-platform manner. + * This code supports the dl API under UNIX and the windows DLL API. + * + * It allows users to conjure up DLL code and retrieve functions from + * that library. For more information, see the CodingWithDLLsGuide + * + */ + +# if defined(WIN32) +# include "sys/Conf.h" +# define DLL_PUBLIC_FUNCTION extern "C" __declspec (dllexport) +typedef HINSTANCE DYNAMIC_LIBRARY; +typedef FARPROC DLL_FUNCTION_PTR; +# else +# include +# define DLL_FLAGSET RTLD_LAZY +# define DLL_PUBLIC_FUNCTION extern "C" +typedef void* DYNAMIC_LIBRARY; +typedef void* DLL_FUNCTION_PTR; +# endif + +#include "except/Exception.h" +#include "sys/Err.h" + + +namespace sys +{ + +/*! + * \class DLLException + * \brief Exception class for DLLs + * + * This class behaves like its parent, except that it + * appends the system or DLL API error that caused the exception + */ +class DLLException : public except::Exception +{ +public: + /*! + * Constructor. + */ + DLLException() + { + adjustMessage(); + } + + /*! + * Construct from a base message. Appends the system-specific + * dll error + * \param message The base message + */ + DLLException(const char* message) : + except::Exception(message) + { + adjustMessage(); + } + + /*! + * Construct from a base message. Appends the system-specific + * dll error + * \param message The base message + */ + DLLException(const std::string& message) : + except::Exception(message) + { + adjustMessage(); + } + + //! Destructor + virtual ~DLLException() + {} + + /*! + * This tacks on the system or API error message + * to the original base message. + */ + virtual void adjustMessage(); +}; + +/*! + * \class DLL + * \brief Dynamically link a library in a system-independent fashion + * + * This is a class to load a DLL (.dll or .so) at runtime. This + * uses the dl API for unix and the windows DLL stuff. Here is an + * example of DLL usage: + * + * DLL dll( "my_dll" ); + * dll.retrieve( "my_function" )(); + * DLL_FUNCTION_PTR ptr = dll.retrieve( "my_function_2" ); + * ptr(); + * + * For more information of coding with dll's see the + * CodingWithDLLsGuide + */ + + +class DLL +{ +public: + + /*! + * Construct a library object, but dont populate or load it + * If you use this method, you must call load() separately + */ + DLL(); + /*! + * Construct a load a libray object. Dont call load() if you + * have called this constructor, unless you unload() first + * \param libName The name of the library + */ + DLL( const std::string& libName ) + { + load( libName ); + } + /*! + * Destructor. This auto-closes the DLL if you didn't call + * unload() explicitly. + * + */ + virtual ~DLL() + { + if ( mLib ) + { + try + { + unload(); + } + catch (...) + { + } + } + } + + /*! + * Load the library by the name given. + * This also sets the internal member mLibName. + * \param libName The library name to load + */ + void load( const std::string& libName ); + + /*! + * Unload the library explicitly. This resets + * the member fields. + */ + void unload(); + + /*! + * Retrieve a function pointer by function name from + * a previously loaded library. The libray must have + * been previously loaded using the load() function, either + * directly or indirectly. + * \param functionName The name of the function to retrieve + * + */ + DLL_FUNCTION_PTR + retrieve( const std::string& functionName ); + + /*! + * Get the name of the library that is currently loaded + * \return The library name + */ + std::string getLibName() const + { + return mLibName; + } + +protected: + //! The library by name + std::string mLibName; + + //! The library by handle + DYNAMIC_LIBRARY mLib; + +}; + + +} + +#endif diff --git a/modules/c++/sys/include/sys/DateTime.h b/modules/c++/sys/include/sys/DateTime.h new file mode 100644 index 000000000..a775f7772 --- /dev/null +++ b/modules/c++/sys/include/sys/DateTime.h @@ -0,0 +1,177 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2012, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __SYS_DATE_TIME_H__ +#define __SYS_DATE_TIME_H__ + +#include +#include + +namespace sys +{ + +/*! + * Representation of a date/time structure. + */ +class DateTime +{ +protected: + int mYear; + int mMonth; + int mDayOfMonth; + int mDayOfWeek; + int mDayOfYear; + int mHour; + int mMinute; + double mSecond; + double mTimeInMillis; + + // Turn a tm struct into a double + double toMillis(tm t) const; + + /*! + * Set the time to right now. + * Uses time() or if HAVE_SYS_TIME_H is defined, + * gettimeofday() for usec precision. + */ + void setNow(); + + //! @brief Set members from the millis value. + void fromMillis(); + + //! @brief Set members from the tm struct value. + virtual void fromMillis(const tm& t); + + //! @brief Set the millis value from the members + virtual void toMillis() = 0; + + //! @brief Provides the time as a 'tm' + void getTime(tm& t) const; + + //! @brief Given seconds since the epoch, provides the time + virtual void getTime(time_t numSecondsSinceEpoch, tm& t) const = 0; + +public: + DateTime(); + virtual ~DateTime(); + + //! Return month {1,12} + int getMonth() const { return mMonth; } + //! Return day of month {1,31} + int getDayOfMonth() const { return mDayOfMonth; } + //! Return day of week {1,7} + int getDayOfWeek() const { return mDayOfWeek; } + //! Return day of year {1,366} + int getDayOfYear() const { return mDayOfYear; } + //! Return hour {0,23} + int getHour() const { return mHour; } + //! Return minute {0,59} + int getMinute() const { return mMinute; } + //! Return second {0,59} + double getSecond() const { return mSecond; } + //! Return millis since 1 Jan 1970 + double getTimeInMillis() const { return mTimeInMillis; } + //! Return the current year + int getYear() const { return mYear; } + + // ! Given the {1,12} month return the alphabetic equivalent + static std::string monthToString(int month); + // ! Given the {1,7} day of the week return the alphabetic equivalent + static std::string dayOfWeekToString(int dayOfWeek); + + // ! Given the {1,12} month return the abbreviated alphabetic equivalent + static std::string monthToStringAbbr(int month); + // ! Given the {1,7} day, return the abbreviated alphabetic equivalent + static std::string dayOfWeekToStringAbbr(int dayOfWeek); + + // ! Given the alphabetic or abbreviated version return {1,12} equivalent + // Acceptable input "August" or "Aug" would return 8 + static int monthToValue(const std::string& month); + // ! Given the alphabetic or abbreviated version return {1,7} equivalent + // Acceptable input "Wednesday" or "Wed" would return 4 + static int dayOfWeekToValue(const std::string& dayOfWeek); + + // Setters + void setMonth(int month); + void setDayOfMonth(int dayOfMonth); + void setHour(int hour); + void setMinute(int minute); + void setSecond(double second); + void setTimeInMillis(double time); + void setYear(int year); + + /*! + * format the DateTime string + * y = year (YYYY) + * M = month (MM) + * d = day (DD) + * H = hour (hh) + * m = minute (mm) + * s = second (ss) + */ + std::string format(const std::string& formatStr) const; + + /** + * @name Logical Operators. + * @brief Logical comparison operators. + * + * @param rhs The object to compare against. + * + * @return true if comparison holds, false otherwise. + */ + //@{ + bool operator<(const DateTime& rhs) const + { + return (mTimeInMillis < rhs.mTimeInMillis); + } + + bool operator<=(const DateTime& rhs) const + { + return (mTimeInMillis <= rhs.mTimeInMillis); + } + + bool operator>(const DateTime& rhs) const + { + return (mTimeInMillis > rhs.mTimeInMillis); + } + + bool operator>=(const DateTime& rhs) const + { + return (mTimeInMillis >= rhs.mTimeInMillis); + } + + bool operator==(const DateTime& rhs) const + { + return (mTimeInMillis == rhs.mTimeInMillis); + } + + bool operator!=(const DateTime& rhs) const + { + return !operator==(rhs); + } + //@} +}; + +} + +#endif//__SYS_DATE_TIME_H__ diff --git a/modules/c++/sys/include/sys/Dbg.h b/modules/c++/sys/include/sys/Dbg.h new file mode 100644 index 000000000..06aabd521 --- /dev/null +++ b/modules/c++/sys/include/sys/Dbg.h @@ -0,0 +1,124 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __DBG_H__ +#define __DBG_H__ + +#include +#include +#include +#include + +#if defined(__sgi) || defined(__sgi__) +# include +#else +# include +#endif + +#ifndef DEBUG_STREAM +#define DEBUG_STREAM stderr +#endif + +/*! \file Dbg.h + * \brief Debgging macros and functions. + * + * Used primarily to trace and record information for debugging. + * By defining __DEBUG, these macros are turned on -- otherwise, + * they are ignored. + * + * A quick macro explanation: + * \par __DEBUG + * Only die_printf will still function if __DEBUG is not defined. All other + * functions and macros in this file will be turned off + * + * \par DEBUG_STREAM + * This is a FILE*. you can define it easily to stderr or stdout. Other + * definitions take some work + * + * \par EVAL(X) + * Give this macro any variable and when defined, it will dump the name and + * current value of that variable in the format x=6, along with the file and + * line. If __DEBUG_SHORTEN_EVAL is defined, it will not include file and + * line number: sometimes that information can be tedious. + * + * \par DUMP(T, X) + * Give this macro any variable and a type (%x, etc.) and it will write it + * and its value with a file and line number. + * + * \par HERE() + * Place this macro anywhere in the code, and when it is reached, it will + * print the file and line number to DEBUG_STREAM + * + * \par TRACE(X) + * Place this macro anywhere in the code that you want to see, as-is. + * It will first print the code, and then evaluate it: + * TRACE(printf("hello\n")); + * + * \par ASSERT_OR(ASSERTION, ELSE) + * This macro gives an alternative to quit. ELSE could be a function to + * open emacs, for instance, with the file in question at the line number + * in question. + */ + +namespace sys +{ +/*! + * Prints to DEBUG_STREAM if __DEBUG is defined + * \param format + * \param ... Put in any format value here + */ +void dbgPrintf(const char *format, ...); + +/*! + * Prints to DEBUG_STREAM and kills the program + * \param format + * \param ... Put in any format value here + */ +void diePrintf(const char *format, ...); +} + +#define dbg_printf sys::dbgPrintf +#define die_printf sys::diePrintf +#define dbg_ln(STR) dbg_printf("[%s, %d]: '%s'\n", __FILE__, __LINE__, STR) + +#ifdef __DEBUG + +#ifndef __DEBUG_SHORTEN_EVAL + #define EVAL(X) std::cout << '(' << __FILE__ << ',' <<__LINE__ << ") "#X"=" << X << std::endl +#else + #define EVAL(X) std::cout << " "#X"=" << X << std::endl +#endif + #define DUMP(T, X) printf(" (%s:%d): "#X"="#T"\n", __FILE__, __LINE__, X) + #define HERE() printf(" (%s:%d)\n", __FILE__, __LINE__) + #define TRACE(X) printf(" (%s:%d): "#X"\n", __FILE__, __LINE__); X + #define ASSERT_OR(ASSERTION, ELSE) { if (ASSERTION) { 1; } else { dbg_printf("(%s, %d): Assertion failed: "#ASSERTION"\n", __FILE__, __LINE__); ELSE; exit(EXIT_FAILURE); } } + +#else + #define EVAL(X) 1 + #define DUMP(T, X) 1 + #define HERE() 1 + #define TRACE(X) X + #define ASSERT_OR(A, E) 1 +#endif + +#endif // __DBG_H__ diff --git a/modules/c++/sys/include/sys/DirectoryEntry.h b/modules/c++/sys/include/sys/DirectoryEntry.h new file mode 100644 index 000000000..21f99eaab --- /dev/null +++ b/modules/c++/sys/include/sys/DirectoryEntry.h @@ -0,0 +1,159 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __SYS_DIRECTORY_ENTRY_H__ +#define __SYS_DIRECTORY_ENTRY_H__ + +#include "except/Exception.h" +#include "sys/OS.h" +#include "sys/Path.h" + + +namespace sys +{ +class DirectoryEntry +{ +public: + class Iterator; + friend class Iterator; + + DirectoryEntry(const Path& path) + { + if (!path.exists() || !path.isDirectory()) + throw except::FileNotFoundException(Ctxt(path.getPath())); + + mCurrent = mDir.findFirstFile(path.getPath()); + mFirst.reset(this); + mLast.reset(NULL); + + } + + /* Dont worry about this for now + DirectoryEntry& operator=(const Path& path) + { + if (!path.exists() || !path.isDirectory()) + throw except::NoSuchFileException(Ctxt(path)); + + mCurrent = mDir.findFirstFile(path.getPath()); + mFirst.reset(this); + mLast.reset(NULL); + return *this; + } + */ + + DirectoryEntry(const std::string& dirName) : + mDirName(dirName) + { + mCurrent = mDir.findFirstFile(dirName); + mFirst.reset(this); + mLast.reset(NULL); + } + virtual ~DirectoryEntry() + {} + virtual void next() + { + mCurrent = mDir.findNextFile(); + } + virtual std::string getCurrent() const + { + return mCurrent; + } + virtual std::string getName() const + { + return mDirName; + } + + class Iterator + { + public: + Iterator() : mEntry(NULL) + {} + explicit Iterator(DirectoryEntry* dirEntry) : mEntry(dirEntry) + {} + + + void reset(DirectoryEntry* dirEntry) + { + mEntry = dirEntry; + } + Iterator& operator++() + { + mEntry->next(); + if (mEntry->mCurrent.empty()) + mEntry = NULL; + return *this; + } + std::string operator*() const + { + if (mEntry->mCurrent.empty()) + throw except::NullPointerReference(Ctxt( + "DirectoryEntry::Iterator NULL entry not allowed")); + return std::string(mEntry->mCurrent); + } + DirectoryEntry* get() const + { + return mEntry; + } + + DirectoryEntry* operator->() const + { + return get(); + } + + private: + DirectoryEntry* mEntry; + + }; + + const Iterator& begin() const + { + return mFirst; + } + const Iterator& end() const + { + return mLast; + } + + +private: + Iterator mFirst; + Iterator mLast; + std::string mCurrent; + std::string mDirName; + Directory mDir; + // DirectoryEntry mDirLast; + + +}; + + + +} + +bool operator==(const sys::DirectoryEntry::Iterator& lhs, + const sys::DirectoryEntry::Iterator& rhs); + +bool operator!=(const sys::DirectoryEntry::Iterator& lhs, + const sys::DirectoryEntry::Iterator& rhs); + +#endif diff --git a/modules/c++/sys/include/sys/Err.h b/modules/c++/sys/include/sys/Err.h new file mode 100644 index 000000000..10298699d --- /dev/null +++ b/modules/c++/sys/include/sys/Err.h @@ -0,0 +1,182 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __SYS_ERR_H__ +#define __SYS_ERR_H__ + +/*! + * \file Err.h + * \brief Errno like object + * + * This object is very much like errno or the GetLastError() function + * in Win32. It doesnt do anything dazzling. It just reports the + * last error. This class is sometimes useful, because it understands + * that its error id maps to a system string error, and it knows how + * to obtain the error + */ + +#include "sys/Conf.h" +#include + +namespace sys +{ +//! The default value for the Err object. Maps to errno or GetLastError() +const static int __last_err__ = 0; +/*! + * \class Err + * \brief Errno like object + * + * This object is very much like errno or the GetLastError() function + * in Win32. It doesnt do anything dazzling. It just reports the + * last error. This class is sometimes useful, because it understands + * that its error id maps to a system string error, and it knows how + * to obtain the error. + * + */ + +class Err +{ +public: + + /*! + * Copy constructor + * \param err The err to take + */ + Err(const Err& err) + { + mErrId = err.getErrID(); + } + + /*! + * Constructor from int error id + * \param errNum The error to initialize with. Defaults to last + */ + Err(int errNum = __last_err__) + { + setThis(errNum); + } + + /*! + * Assignment operator + * \param err The err to take + */ + Err& operator=(const Err& err) + { + if (&err != this) + { + mErrId = err.getErrID(); + } + return *this; + } + + //! Destructor + virtual ~Err() {} + + /*! + * This is the equivalent of strerror, done in a cross-platform + * manner, wrapped in this class. Prints this object to + * its error string + * \return a string representation of this error + * + */ + virtual std::string toString() const; + + /*! + * Set method + * \param i An int to initialize from + */ + void setThis(int i = __last_err__) + { + if (i == __last_err__) + { + mErrId = getLast(); + } + } + + //! Return the last error + virtual int getLast() const; + + int getErrID() const { return mErrId; } + +protected: + + int mErrId; + +}; + +/*! + * \class SocketErr + * \brief Specialization to handle those weird winsock/bsd errors + * + * The same operations as in Err for sockets + * + */ +class SocketErr : public Err +{ +public: + + /*! + * Copy constructor. Takes a right-hand-side + * \param err An error to initialize from + * + */ + SocketErr(const SocketErr& err) + { + mErrId = err.getErrID(); + } + + /*! + * Constructor + * \param errNum An int to initialize from + * + */ + SocketErr(int errNum = __last_err__) + { + setThis(errNum); + } + + /*! + * Assignment operator + * \param err The err to take + * + */ + SocketErr& operator=(const SocketErr& err) + { + if (&err != this) + { + mErrId = err.getErrID(); + } + return *this; + } + + //! Destructor + virtual ~SocketErr() {} + + //! Redefined for socket errors + virtual int getLast() const; + +}; + +} + +#endif diff --git a/modules/c++/sys/include/sys/Exec.h b/modules/c++/sys/include/sys/Exec.h new file mode 100644 index 000000000..c666d4537 --- /dev/null +++ b/modules/c++/sys/include/sys/Exec.h @@ -0,0 +1,159 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __SYS_EXEC_PIPE_H__ +#define __SYS_EXEC_PIPE_H__ + +#include +#include +#include + +#include "sys/Runnable.h" +#include "sys/Err.h" +#include "sys/ProcessInterface.h" + +#ifdef _WIN32 +#define popen _popen +#define pclose _pclose +#define fileno _fileno +#endif + + +namespace sys +{ + +/*! + * \class Exec + * \brief A good, old-fashioned exec call + * + * This Exec class defines an API for a system-independent + * exec method. The fact that it inherits the Runnable interface + * allows us to use it from within a Process to create a + * 'system()'-like functionality. + */ +class Exec : public sys::Runnable +{ +public: + /*! + * Execute a command on the run() function + * \param cmd The command to exec() + */ + Exec( const std::string& cmd ) : + mCmd(cmd) + { + } + + //! Destructor + virtual ~Exec() + {} + + /*! + * Execute a command + */ + virtual void run() + { + if (::system(mCmd.c_str()) == -1) + { + sys::Err err; + throw except::IOException( + Ctxt("Unable to run system command: " + err.toString())); + } + } + +protected: + //! A command + std::string mCmd; +}; + +/*! + * \class ExecPipe + * \brief opens a child process and connects a pipe + * to read back the std::cout + */ +class ExecPipe : Exec +{ + +public: + + /*! + * Constructor -- + * Kicks off child process and connects a pipe to the std::cout + * + * \param cmd - command line string to run + */ + ExecPipe(const std::string& cmd) : + Exec(cmd), + mOutStream(NULL) + { + } + + //! start the child process and connect the pipe + virtual void run() + { + mOutStream = popen(mCmd.c_str(), "r"); + if (mOutStream == NULL) + { + sys::Err err; + throw except::IOException( + Ctxt("Unable to open stream: " + err.toString())); + } + } + + //! cleanup the stream if not done already + ~ExecPipe() + { + if (mOutStream) + { + try + { + closePipe(); + } + catch (...) + { + } + } + } + + //! make available the pipe + const FILE* getPipe() const { return mOutStream; } + + //! make available the pipe + FILE* getPipe() { return mOutStream; } + + //! closes the stream connected to the child process -- + //! platform specific implementation + int closePipe(); + +protected: + + FILE* mOutStream; + +private: + + //! Noncopyable + ExecPipe(const ExecPipe& ); + const ExecPipe& operator=(const ExecPipe& ); +}; + +} + +#endif diff --git a/modules/c++/sys/include/sys/File.h b/modules/c++/sys/include/sys/File.h new file mode 100644 index 000000000..d30d4004e --- /dev/null +++ b/modules/c++/sys/include/sys/File.h @@ -0,0 +1,247 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __SYS_FILE_H__ +#define __SYS_FILE_H__ + +#include "sys/Conf.h" +#include "sys/SystemException.h" +#include "sys/Path.h" + +#ifdef WIN32 +# define _SYS_SEEK_CUR FILE_CURRENT +# define _SYS_SEEK_SET FILE_BEGIN +# define _SYS_SEEK_END FILE_END +# define _SYS_CREAT OPEN_ALWAYS +# define _SYS_OPEN_EXISTING OPEN_EXISTING +# define _SYS_TRUNC 8 +# define _SYS_RDONLY GENERIC_READ +# define _SYS_WRONLY GENERIC_WRITE +# define _SYS_RDWR GENERIC_READ|GENERIC_WRITE +# define SYS_INVALID_HANDLE INVALID_HANDLE_VALUE +typedef HANDLE _SYS_HANDLE_TYPE; +#else +# define _SYS_DEFAULT_PERM 0644 +# define _SYS_MAX_READ_ATTEMPTS 100 +# define _SYS_SEEK_CUR SEEK_CUR +# define _SYS_SEEK_SET SEEK_SET +# define _SYS_SEEK_END SEEK_END +# define _SYS_CREAT O_CREAT +# define _SYS_OPEN_EXISTING 0 +# define _SYS_TRUNC O_TRUNC +# define _SYS_RDONLY O_RDONLY +# define _SYS_WRONLY O_WRONLY +# define _SYS_RDWR O_RDWR +# define SYS_INVALID_HANDLE -1 +typedef int _SYS_HANDLE_TYPE; +#endif + +/*! + * \class File + * \brief Cross-platform API for file descriptor access + * + * This API exists primarily as a wrapper for the system + * OS behavior. It is intended that this class be capable + * of reading > 2GB files on all platforms. + * + */ + +namespace sys +{ +class File +{ +public: + + enum + { + FROM_START = _SYS_SEEK_SET, + FROM_CURRENT = _SYS_SEEK_CUR, + FROM_END = _SYS_SEEK_END, + CREATE = _SYS_CREAT, + EXISTING = _SYS_OPEN_EXISTING, + TRUNCATE = _SYS_TRUNC, + READ_ONLY = _SYS_RDONLY, + WRITE_ONLY = _SYS_WRONLY, + READ_AND_WRITE = _SYS_RDWR + }; + + /*! + * Default constructor. Does nothing + */ + File() : + mHandle(SYS_INVALID_HANDLE) + { + } + + /*! + * Constructor. Initializes to a file. + * \param str A file name to open + * \param accessFlags File access flags + * \param creationFlags File creation flags + */ + File(const Path& path, int accessFlags = READ_ONLY, + int creationFlags = EXISTING) throw (sys::SystemException) + { + create(path.getPath(), accessFlags, creationFlags); + } + + File(const Path& parent, std::string name, int accessFlags = READ_ONLY, + int creationFlags = EXISTING) throw (sys::SystemException) + { + create(parent.join(name).getPath(), accessFlags, creationFlags); + } + + /*! + * Constructor. Initializes to a file. + * \param str A file name to open + * \param accessFlags File access flags + * \param creationFlags File creation flags + */ + File(std::string str, int accessFlags = READ_ONLY, + int creationFlags = EXISTING) throw (sys::SystemException) + { + create(str, accessFlags, creationFlags); + } + + /*! + * Destructor. Closes file if open. + */ + ~File() + { + if (isOpen()) + close(); + } + + /*! + * Is the file open? + * \return true if open, false if invalid handle + */ + bool isOpen() + { + return (mHandle != SYS_INVALID_HANDLE); + } + + /*! + * Return the underlying file handle + * + */ + _SYS_HANDLE_TYPE getHandle() + { + return mHandle; + } + + sys::Path getPath() const + { + return sys::Path(mPath); + } + + inline std::string getName() const + { + return getPath().split().second; + } + + /*! + * Initialize the object to a file. + * \param str A file name to open + * \param accessFlags File access flags + * \param creationFlags File creation flags + */ + void create(const std::string& str, int accessFlags, + int creationFlags) throw (sys::SystemException); + + /*! + * Read from the File into a buffer 'size' bytes. + * Blocks. + * If size is 0, no OS level read operation occurs. + * If size is < 0, an exception is thrown. + * If size is > length of file, an exception occurs. + * + * \param buffer The buffer to put to + * \param size The number of bytes + */ + void readInto(char* buffer, Size_T size) throw (sys::SystemException); + + /*! + * Write from a buffer 'size' bytes into the + * file. + * Blocks. + * If size is 0, no OS level write operation occurs. + * If size is < 0, an exception is thrown. + * + * \param buffer The buffer to read from + * \param size The number of bytes to write out + */ + void writeFrom(const char* buffer, + Size_T size) throw (sys::SystemException); + + /*! + * Seek to the specified offset, relative to 'whence.' + * Valid values are FROM_START, FROM_CURRENT, FROM_END. + * + * \return Global offset location. + */ + + sys::Off_T seekTo(sys::Off_T offset, + int whence) throw (sys::SystemException); + + /*! + * Report current offset within file. + * + * \return Current offset; + */ + sys::Off_T getCurrentOffset() throw (sys::SystemException) + { + return seekTo(0, sys::File::FROM_CURRENT); + } + + /*! + * Report the length of the file. + * \return The length + */ + sys::Off_T length() throw (sys::SystemException); + + /*! + * Returns the last modified time of the file, in millis. + * \return last modified time + */ + sys::Off_T lastModifiedTime() throw (sys::SystemException); + + /*! + * Flush the file to disk + */ + void flush(); + + /*! + * Close the handle. + */ + void close(); + +protected: + _SYS_HANDLE_TYPE mHandle; + std::string mPath; + +}; + +} + +#endif + diff --git a/modules/c++/sys/include/sys/FileFinder.h b/modules/c++/sys/include/sys/FileFinder.h new file mode 100644 index 000000000..c27fc4ea8 --- /dev/null +++ b/modules/c++/sys/include/sys/FileFinder.h @@ -0,0 +1,163 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __SYS_FILE_FINDER_H__ +#define __SYS_FILE_FINDER_H__ + +#include +#include + +namespace sys +{ + +/** + * Predicate interface for all entries + */ +struct FilePredicate : std::unary_function +{ + virtual ~FilePredicate() {} + virtual bool operator()(const std::string& entry) const = 0; +}; + +/** + * Predicate interface for existance + */ +struct ExistsPredicate : FilePredicate +{ + virtual ~ExistsPredicate() {} + virtual bool operator()(const std::string& entry) const; +}; + +/** + * Predicate that matches files only (no directories) + */ +struct FileOnlyPredicate: public FilePredicate +{ + virtual ~FileOnlyPredicate() {} + virtual bool operator()(const std::string& entry) const; +}; + +/** + * Predicate that matches directories only (no files) + */ +struct DirectoryOnlyPredicate: public FilePredicate +{ + virtual ~DirectoryOnlyPredicate() {} + virtual bool operator()(const std::string& entry) const; +}; + +/** + * Predicate that matches directories only (no files) + */ +struct FragmentPredicate : public FilePredicate +{ +public: + FragmentPredicate(const std::string& fragment, bool ignoreCase = true); + bool operator()(const std::string& entry) const; + +private: + std::string mFragment; + bool mIgnoreCase; + +}; + + +/** + * Predicate interface for filtering files with a specific extension + * This method will not match '.xxx.yyy' type patterns, since the + * splitting routines will only find '.yyy'. See re::RegexPredicate + * for a more useful finder. + */ +class ExtensionPredicate: public FileOnlyPredicate +{ +public: + ExtensionPredicate(const std::string& ext, bool ignoreCase = true); + bool operator()(const std::string& filename) const; + +private: + std::string mExt; + bool mIgnoreCase; +}; + +/** + * Predicate that does logical not of another predicate (ie !) + */ +class NotPredicate : public FilePredicate +{ +public: + NotPredicate(FilePredicate* filter, bool ownIt = false); + virtual ~NotPredicate(); + + virtual bool operator()(const std::string& entry) const; + +protected: + typedef std::pair PredicatePair; + PredicatePair mPredicate; +}; + + +/** + * The LogicalPredicate class allows you to chain many + * predicates using the logical && or || + */ +class LogicalPredicate : public FilePredicate +{ +public: + LogicalPredicate(bool orOperator = true); + virtual ~LogicalPredicate(); + + sys::LogicalPredicate& addPredicate(FilePredicate* filter, + bool ownIt = false); + + virtual bool operator()(const std::string& entry) const; + +protected: + bool mOrOperator; + typedef std::pair PredicatePair; + std::vector mPredicates; +}; + +/** + * \class FileFinder + * + * The FileFinder class allows you to search for + * files/directories in a clean way. + */ +class FileFinder +{ +public: + FileFinder() {} + ~FileFinder() {} + + /** + * Perform the search + * \return a std::vector of paths that match + */ + static std::vector search( + const FilePredicate& filter, + const std::vector& searchPaths, + bool recursive = false); +}; + +} + +#endif diff --git a/modules/c++/sys/include/sys/LocalDateTime.h b/modules/c++/sys/include/sys/LocalDateTime.h new file mode 100755 index 000000000..e4e558629 --- /dev/null +++ b/modules/c++/sys/include/sys/LocalDateTime.h @@ -0,0 +1,95 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2012, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __SYS_LOCAL_DATE_TIME_H__ +#define __SYS_LOCAL_DATE_TIME_H__ + +#include + +namespace sys +{ + +/*! + * Representation of a local date/time structure. + */ +class LocalDateTime : public DateTime +{ +protected: + int mDST; + + //! @brief Set members from the tm struct value. + virtual void fromMillis(const tm& t); + + /** + * @brief Set the millis value from the members + */ + virtual void toMillis(); + + // ! Given seconds since the epoch, provides the local time + virtual void getTime(time_t numSecondsSinceEpoch, tm& t) const; + +public: + static const char DEFAULT_DATETIME_FORMAT[]; + + /*! + * Construct as current date and time (localtime). + */ + LocalDateTime(); + /*! + * Construct with time values. Date will be today. + */ + LocalDateTime(int hour, int minute, double second); + /*! + * Construct with date values. Time will be 00:00:00. + */ + LocalDateTime(int year, int month, int day); + /*! + * Construct with date and time values. + */ + LocalDateTime(int year, int month, int day, + int hour, int minute, double second); + /*! + * Construct with time in milliseconds. + */ + LocalDateTime(double timeInMillis); + + //! Return the Daylight Savings Time flag (true = on, false = off) + bool getDST() const { return mDST == 1; } + + //! Set the Daylight Savings Time flag (true = on, false = off) + void setDST(bool isDST); + + // unhide in the base class format method + using DateTime::format; + + /*! + * The default formatting looks like this: + * %y%-M%-d_%H:%m:%s + * 2011-10-19_11:59:46 + */ + std::string format() const; +}; + +} + +#endif//__SYS_LOCAL_DATE_TIME_H__ diff --git a/modules/c++/sys/include/sys/Mutex.h b/modules/c++/sys/include/sys/Mutex.h new file mode 100644 index 000000000..ba8ba1f5c --- /dev/null +++ b/modules/c++/sys/include/sys/Mutex.h @@ -0,0 +1,83 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __SYS_MUTEX_H__ +#define __SYS_MUTEX_H__ +/** + * \file + * \brief Include the right mutex. + * + * This file will auto-select the mutex of choice, + * if one is to be defined. + * \note We need to change the windows part to check _MT + * because that is how it determines reentrance! + * + */ +# if defined(_REENTRANT) + +# if defined(USE_NSPR_THREADS) +# include "sys/MutexNSPR.h" +namespace sys +{ +typedef MutexNSPR Mutex; +} +// If they explicitly want posix +# elif defined(__POSIX) +# include "sys/MutexPosix.h" +namespace sys +{ +typedef MutexPosix Mutex; +} +# elif defined(WIN32) +# include "sys/MutexWin32.h" +namespace sys +{ +typedef MutexWin32 Mutex; +} + +/* # elif defined(USE_BOOST) */ +/* # include "MutexBoost.h" */ +/* typedef MutexBoost Mutex; */ +# elif defined(__sun) && !defined(__POSIX) +# include "sys/MutexSolaris.h" +namespace sys +{ +typedef MutexSolaris Mutex; +} +# elif defined(__sgi) && !defined(__POSIX) +# include "sys/MutexIrix.h" +namespace sys +{ +typedef MutexIrix Mutex; +} +# else +# include "sys/MutexPosix.h" +namespace sys +{ +typedef MutexPosix Mutex; +} +# endif // Which thread package? + +# endif // Are we reentrant? + +#endif // End of header diff --git a/modules/c++/sys/include/sys/MutexInterface.h b/modules/c++/sys/include/sys/MutexInterface.h new file mode 100644 index 000000000..a4135d045 --- /dev/null +++ b/modules/c++/sys/include/sys/MutexInterface.h @@ -0,0 +1,81 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __SYS_MUTEX_INTERFACE_H__ +#define __SYS_MUTEX_INTERFACE_H__ + + + +#if defined(_REENTRANT) +#include +#include "sys/SystemException.h" +#include "sys/Dbg.h" + +namespace sys +{ + +/*! + * \class MutexInterface + * \brief The interface for any mutex + * + * This class defines the interface for any mutex in any package that + * is wrapped herein + */ +class MutexInterface +{ +public: + //! Constructor + MutexInterface() + { +#ifdef THREAD_DEBUG + dbg_printf("Creating a mutex\n"); +#endif + + } + + //! Destructor + virtual ~MutexInterface() + { +#ifdef THREAD_DEBUG + dbg_printf("Destroying a mutex\n"); +#endif + + } + + /*! + * Lock the mutex up. + */ + virtual void lock() = 0; + + /*! + * Unlock the mutex. + */ + virtual void unlock() = 0; + +}; + +} + +#endif // Are we reentrant? + +#endif diff --git a/modules/c++/sys/include/sys/MutexIrix.h b/modules/c++/sys/include/sys/MutexIrix.h new file mode 100644 index 000000000..883bf998a --- /dev/null +++ b/modules/c++/sys/include/sys/MutexIrix.h @@ -0,0 +1,81 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __SYS_MUTEX_IRIX_H__ +#define __SYS_MUTEX_IRIX_H__ + + +#if defined(__sgi) && defined(_REENTRANT) && !defined(__POSIX) +#include "sys/SyncFactoryIrix.h" +#include "sys/MutexInterface.h" + +namespace sys +{ +/*! + * \class MutexIrix + * \brief The pthreads implementation of a mutex + * + * Implements a pthread mutex and wraps the outcome + * + */ +class MutexIrix : public MutexInterface +{ +public: + //! Constructor + MutexIrix(); + + //! Destructor + virtual ~MutexIrix(); + + /*! + * Lock the mutex. + */ + virtual void lock(); + + /*! + * Unlock the mutex. + */ + virtual void unlock(); + + /*! + * Returns the native type. + */ + ulock_t*& getNative(); + + /*! + * Return the type name. This function is essentially free, + * because it is static RTTI. + */ + const char* getNativeType() const + { + return typeid(mNative).name(); + } + +private: + ulock_t* mNative; +}; + +} + +#endif +#endif diff --git a/modules/c++/sys/include/sys/MutexNSPR.h b/modules/c++/sys/include/sys/MutexNSPR.h new file mode 100644 index 000000000..878957727 --- /dev/null +++ b/modules/c++/sys/include/sys/MutexNSPR.h @@ -0,0 +1,75 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __SYS_NSPR_MUTEX_H__ +#define __SYS_NSPR_MUTEX_H__ + +#if defined(USE_NSPR_THREADS) && defined(_REENTRANT) + +#include "sys/MutexInterface.h" +#include +#include +#include + + +namespace sys +{ +/*! + * \class MutexNSPR + * \brief This is a Netscape Portable Runtime mutex + * implementation + * + * Use NSPR thread package to make platform independent + * threading + */ +class MutexNSPR : public MutexInterface +{ +public: + //! Constructor. Create a new mutex + MutexNSPR(); + + //! Destroy the native mutex + + ~MutexNSPR(); + /*! + * Lock a NSPR mutex + */ + void lock(); + + /*! + * Unlock NSPR mutex. + */ + virtual void unlock(); + + /*! + * Returns the native type. + */ + PRLock*& getNative(); + +private: + PRLock* mNative; +}; + +} +# endif // NSPR +#endif // Header diff --git a/modules/c++/sys/include/sys/MutexPosix.h b/modules/c++/sys/include/sys/MutexPosix.h new file mode 100644 index 000000000..1d765da13 --- /dev/null +++ b/modules/c++/sys/include/sys/MutexPosix.h @@ -0,0 +1,82 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __SYS_MUTEX_POSIX_H__ +#define __SYS_MUTEX_POSIX_H__ + +#if defined(__POSIX) && defined(_REENTRANT) +#include "sys/MutexInterface.h" +#include + + + +namespace sys +{ +/*! + * \class MutexPosix + * \brief The pthreads implementation of a mutex + * + * Implements a pthread mutex and wraps the outcome + * + */ +class MutexPosix : public MutexInterface +{ +public: + //! Constructor + MutexPosix(); + + //! Destructor + virtual ~MutexPosix(); + + /*! + * Lock the mutex. + */ + virtual void lock(); + + /*! + * Unlock the mutex. + */ + virtual void unlock(); + + /*! + * Returns the native type. + */ + pthread_mutex_t& getNative(); + + /*! + * Return the type name. This function is essentially free, + * because it is static RTTI. + */ + const char* getNativeType() const + { + return typeid(mNative).name(); + } + +private: + pthread_mutex_t mNative; +}; +} + +#endif +#endif + diff --git a/modules/c++/sys/include/sys/MutexSolaris.h b/modules/c++/sys/include/sys/MutexSolaris.h new file mode 100644 index 000000000..7b1f89207 --- /dev/null +++ b/modules/c++/sys/include/sys/MutexSolaris.h @@ -0,0 +1,82 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __SYS_THREAD_SOLARIS_MUTEX_H__ +#define __SYS_THREAD_SOLARIS_MUTEX_H__ + + +#if defined(__sun) && defined(_REENTRANT) && !defined(__POSIX) + +#include +#include +#include "sys/MutexInterface.h" + +namespace sys +{ +/*! + * \class MutexSolaris + * \brief The solaris threads implementation of a mutex + * + * Implements a solaris thread mutex and wraps the outcome + * + */ +class MutexSolaris : public MutexInterface +{ +public: + //! Constructor + MutexSolaris(); + + //! Destructor + virtual ~MutexSolaris(); + + /*! + * Lock the mutex. + */ + virtual void lock(); + + /*! + * Unlock the mutex. + */ + virtual void unlock(); + + /*! + * Returns the native type. + */ + mutex_t& getNative(); + + /*! + * Return the type name. This function is essentially free, + * because it is static RTTI. + */ + const char* getNativeType() const + { + return typeid(mNative).name(); + } + +private: + mutex_t mNative; +}; +} + +#endif +#endif diff --git a/modules/c++/sys/include/sys/MutexWin32.h b/modules/c++/sys/include/sys/MutexWin32.h new file mode 100644 index 000000000..ac40d6e5b --- /dev/null +++ b/modules/c++/sys/include/sys/MutexWin32.h @@ -0,0 +1,70 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __SYS_MUTEX_WIN32_H__ +#define __SYS_MUTEX_WIN32_H__ + +#if defined(WIN32) && defined(_REENTRANT) +#if !defined(USE_NSPR_THREADS) && !defined(__POSIX) + +#include "sys/MutexInterface.h" + +namespace sys +{ +class MutexWin32 : public MutexInterface +{ +public: + //! \todo Add string name option + MutexWin32(); + virtual ~MutexWin32(); + /*! + * Lock the mutex. + */ + virtual void lock(); + + /*! + * Unlock the mutex. + */ + virtual void unlock(); + + /*! + * Returns the native type. + */ + HANDLE& getNative(); + + /*! + * Return the type name. This function is essentially free, + * because it is static RTTI. + */ + const char* getNativeType() const + { + return typeid(mNative).name(); + } + +private: + HANDLE mNative; +}; +} +#endif +#endif +#endif diff --git a/modules/c++/sys/include/sys/OS.h b/modules/c++/sys/include/sys/OS.h new file mode 100644 index 000000000..1b14b84b0 --- /dev/null +++ b/modules/c++/sys/include/sys/OS.h @@ -0,0 +1,46 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __SYS_OS_H__ +#define __SYS_OS_H__ + +#include "sys/AbstractOS.h" + +#if defined(WIN32) +# include "sys/OSWin32.h" +namespace sys +{ +typedef OSWin32 OS; +typedef DirectoryWin32 Directory; +} +#else +# include "sys/OSUnix.h" +namespace sys +{ +typedef OSUnix OS; +typedef DirectoryUnix Directory; +} +#endif + +#endif + diff --git a/modules/c++/sys/include/sys/OSUnix.h b/modules/c++/sys/include/sys/OSUnix.h new file mode 100644 index 000000000..041c09cab --- /dev/null +++ b/modules/c++/sys/include/sys/OSUnix.h @@ -0,0 +1,190 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __SYS_OS_UNIX_H__ +#define __SYS_OS_UNIX_H__ + +#if !defined(WIN32) + +#include "sys/AbstractOS.h" +#include "sys/Conf.h" +#include +#include + +namespace sys +{ +class OSUnix : public AbstractOS +{ +public: + OSUnix() + {} + virtual ~OSUnix() + {} + + virtual std::string getPlatformName() const; + + virtual std::string getNodeName() const; + + /*! + * Get the path delimiter for this operating system. + * For windows, this will be two slashes \\ + * For unix it will be one slash / + * \return The path delimiter + */ + virtual const char* getDelimiter() const + { + return "/"; + } + + /*! + * Gets the username for windows users + * \return The string name of the user + */ + // virtual std::string getUsername() const; + + /*! + * Does this path exist? + * \param path The path to check for + * \return True if it does, false otherwise + */ + virtual bool exists(const std::string& path) const; + + /*! + * Move file with this path name to the newPath + * \return True upon success, false if failure + */ + virtual bool move(const std::string& path, + const std::string& newPath) const; + + /*! + * Does this path resolve to a file? + * \param path The path + * \return True if it does, false if not + */ + virtual bool isFile(const std::string& path) const; + + /*! + * Does this path resolve to a directory? + * \param path The path + * \return True if it does, false if not + */ + virtual bool isDirectory(const std::string& path) const; + + virtual bool makeDirectory(const std::string& path) const; + + + virtual Pid_T getProcessId() const; + + + /*! + * Retrieve the current working directory. + * \return The current working directory + */ + virtual std::string getCurrentWorkingDirectory() const; + + /*! + * Change the current working directory. + * \return true if the directory was changed, otherwise false. + */ + virtual bool changeDirectory(const std::string& path) const; + + /*! + * Get a suitable temporary file name + * \return The file name + */ + virtual std::string getTempName(const std::string& path = ".", + const std::string& prefix = "TMP") const; + + /*! + * Return the size in bytes of a file + * \return The file size + */ + virtual sys::Off_T getSize(const std::string& path) const; + + /** + * Returns the last modified time of the file/directory + */ + virtual sys::Off_T getLastModifiedTime(const std::string& path) const; + + /*! + * This is a system independent sleep function. + * Be careful using timing calls with threads + * \todo I heard usleep is deprecated, and I should + * use nanosleep + * \param milliseconds The params + */ + virtual void millisleep(int milliseconds) const; + + virtual std::string operator[](const std::string& s) const; + + /*! + * Get an environment variable + */ + virtual std::string getEnv(const std::string& s) const; + + /*! + * Set an environment variable + */ + virtual void setEnv(const std::string& var, + const std::string& val, + bool overwrite); + + virtual std::string getDSOSuffix() const; + + virtual size_t getNumCPUs() const; + +protected: + /*! + * Remove file with this pathname + * \return True upon success, false if failure + */ + virtual bool removeFile(const std::string& pathname) const; + + /*! + * Remove directory with this pathname + * \return True upon success, false if failure + */ + virtual bool removeDirectory(const std::string& pathname) const; +}; + + +class DirectoryUnix : public AbstractDirectory +{ +public: + DirectoryUnix() : mDir(NULL) + {} + virtual ~DirectoryUnix() + { + close(); + } + virtual void close(); + virtual std::string findFirstFile(const std::string& dir); + virtual std::string findNextFile(); + DIR* mDir; + +}; + +} + +#endif +#endif diff --git a/modules/c++/sys/include/sys/OSWin32.h b/modules/c++/sys/include/sys/OSWin32.h new file mode 100644 index 000000000..55bdb5ce6 --- /dev/null +++ b/modules/c++/sys/include/sys/OSWin32.h @@ -0,0 +1,215 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __SYS_WIN32_OS_H__ +#define __SYS_WIN32_OS_H__ + +#include "sys/AbstractOS.h" + +#if defined(WIN32) + +/*! + * \file OSWin32.h + * \brief This file provides definitions for the windows layer + * + * This file provides the definitions for the windows layer of + * file manipulation abstraction, etc. + */ + +namespace sys +{ + +/*! + * \class OSWin32 + * \brief The abstraction definition layer for windows + * + * This class is the abstraction layer as defined for + * the windows operating system. + */ +class OSWin32 : public AbstractOS +{ +public: + OSWin32() + {} + virtual ~OSWin32() + {} + virtual std::string getPlatformName() const; + + virtual std::string getNodeName() const; + /*! + * Get the path delimiter for this operating system. + * For windows, this will be two slashes \\ + * For unix it will be one slash / + * \return The path delimiter + */ + virtual const char* getDelimiter() const + { + return "\\"; + } + + /*! + * Determine the username + * \return The username + */ + //virtual std::string getUsername() const; + + + /*! + * Does this path exist? + * NOTE: On Windows a path specifying a directory should not + * end in '\\' or '/' or it will always fail this check + * \param path The path to check for + * \return True if it does, false otherwise + */ + virtual bool exists(const std::string& path) const; + + /*! + * Move file with this path name to the newPath + * Note: this will move (rename) either a file or a directory + * (including its children) either in the same directory or across + * directories. The one caveat is that it will fail on directory + * moves when the destination is on a different volume. + * + * \return True upon success, false if failure + */ + virtual bool move(const std::string& path, + const std::string& newPath) const; + + /*! + * Does this path resolve to a file? + * \param path The path + * \return True if it does, false if not + */ + virtual bool isFile(const std::string& path) const; + + /*! + * Does this path resolve to a directory? + * \param path The path + * \return True if it does, false if not + * \todo Throw if nothing exists?? + */ + virtual bool isDirectory(const std::string& path) const; + + /*! + * Create a directory with for the path specified + * \param path The path to create + * \return True on success, false on failure (since + * you may only create if no such exists) + */ + virtual bool makeDirectory(const std::string& path) const; + + /*! + * Retrieve the current working directory. + * \return The current working directory + */ + virtual std::string getCurrentWorkingDirectory() const; + + /*! + * Change the current working directory. + * \return true if the directory was changed, otherwise false. + */ + virtual bool changeDirectory(const std::string& path) const; + + + virtual Pid_T getProcessId() const; + + /*! + * Get a suitable temporary file name + * \return The file name + * + */ + virtual std::string getTempName(const std::string& path = ".", + const std::string& prefix = "TMP") const; + /*! + * Return the size in bytes of a file + * \return The file size + */ + virtual sys::Off_T getSize(const std::string& path) const; + + virtual sys::Off_T getLastModifiedTime(const std::string& path) const; + + virtual std::string getDSOSuffix() const; + + /*! + * This is a system independent sleep function. + * Be careful using timing calls with threads + * \param milliseconds The params + */ + virtual void millisleep(int milliseconds) const; + + virtual std::string operator[](const std::string& s) const; + + /*! + * Get an environment variable + */ + virtual std::string getEnv(const std::string& s) const; + + /*! + * Set an environment variable + */ + virtual void setEnv(const std::string& var, + const std::string& val, + bool overwrite); + + virtual size_t getNumCPUs() const; + +protected: + /*! + * Remove file with this pathname + * \return True upon success, false if failure + */ + virtual bool removeFile(const std::string& pathname) const; + + /*! + * Remove directory with this pathname + * \return True upon success, false if failure + */ + virtual bool removeDirectory(const std::string& pathname) const; +}; + + + +class DirectoryWin32 : public AbstractDirectory +{ +public: + DirectoryWin32() : mHandle(INVALID_HANDLE_VALUE) + {} + virtual ~DirectoryWin32() + { + close(); + } + virtual void close(); + + virtual std::string findFirstFile(const std::string& dir); + + virtual std::string findNextFile(); + + HANDLE mHandle; + WIN32_FIND_DATA mFileData; + +}; + +} + +#endif +#endif diff --git a/modules/c++/sys/include/sys/Path.h b/modules/c++/sys/include/sys/Path.h new file mode 100644 index 000000000..de846b66d --- /dev/null +++ b/modules/c++/sys/include/sys/Path.h @@ -0,0 +1,261 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __SYS_PATH_H__ +#define __SYS_PATH_H__ + +#include "sys/OS.h" +#include +#include +#include +#include + +/*! + * \file + * \brief This class provides Path-related static utilities. + * + */ + +namespace sys +{ + +class Path +{ +public: + Path(); + Path(const Path& parent, std::string child); + Path(std::string parent, std::string child); + Path(std::string pathName); + Path& operator=(const Path& path); + Path(const Path& path); + ~Path(); + + inline operator std::string() const + { + return mPathName; + } + + //! Shortcut for a std::pair of std::strings + typedef std::pair StringPair; + + /*! + * Normalizes a pathname. Collapses redundant separators and up-level + * references. On Windows, it converts forward slashes to backward slashes. + */ + static std::string normalizePath(const std::string& path); + + inline std::string normalize() const + { + return normalizePath(mPathName); + } + + /*! + * Joins two paths together, using the OS-specific delimiter. + */ + static std::string joinPaths(const std::string& path1, + const std::string& path2); + + inline Path join(const std::string& path) const + { + return joinPaths(mPathName, path); + } + + /*! + * Return a normalized absolutized verion of the pathname supplied. + */ + static std::string absolutePath(const std::string& path); + + inline std::string getAbsolutePath() const + { + return absolutePath(mPathName); + } + + /*! + * Separates a path into its components, and returns a vector of + * them. This splits on both '/' and '\\'. + */ + static std::vector separate(const std::string& path); + + inline std::vector separate() const + { + return separate(mPathName); + } + + /*! + * Splits the path into two components: head & tail. + * + * The tail part will never contain the delim; if path ends in the delim, + * tail will be empty. If there is no delim in path, head will be empty. + */ + static StringPair splitPath(const std::string& path); + + inline StringPair split() const + { + return splitPath(mPathName); + } + + /*! + * Splits the path it into two components: drive & tail. + * + * For systems that do not support drive specifications, drive will always + * be the empty string. drive + tail = path + */ + static StringPair splitDrive(const std::string& path); + + inline StringPair splitDrive() const + { + return splitDrive(mPathName); + } + + /*! + * Splits the pathname into two components: root & ext. + * + * The returned pair will contain the root of the path plus the extension, + * if one exists. You can combine the returned pair to create the original + * path. + */ + static StringPair splitExt(const std::string& path); + + inline StringPair splitExt() const + { + return splitExt(mPathName); + } + + /*! + * Returns the base name of the path supplied. This is the second half of the + * pair returned by splitPath() + */ + static std::string basename(const std::string& path, bool rmvExt = false); + + inline std::string getBasePath(bool removeExt = false) const + { + return sys::Path::basename(mPathName, removeExt); + } + + /*! + * Returns the path delimiter + */ + static const char* delimiter(); + + /*! + * Returns the path separator + */ + static const char* separator(); + + inline bool exists() const + { + return mOS.exists(mPathName); + } + + inline bool isDirectory() const + { + return mOS.isDirectory(mPathName); + } + + inline bool isFile() const + { + return mOS.isFile(mPathName); + } + + inline sys::Off_T lastModified() const + { + return mOS.getLastModifiedTime(mPathName); + } + + inline std::string getPath() const + { + return mPathName; + } + + std::vector list() const; + + /*! + * Creates the directory + * \param makeParents - flag for making any non-existant parent + * directories + */ + inline bool makeDirectory(bool makeParents = false) const + { + if (makeParents) + { + std::vector pathList = separate(mPathName); + Path workingPath; + bool createDir = true; + size_t i = 0; + + // unix puts slash before any path making cwd == root + if (pathList.size() && pathList[0] == ".") + { + workingPath = pathList[0]; + i++; + } + + while (createDir && i < pathList.size()) + { + // create each + workingPath = workingPath.join(pathList[i]); + if (!mOS.exists(workingPath)) + createDir = mOS.makeDirectory(workingPath); + i++; + } + return createDir; + } + else + return mOS.makeDirectory(mPathName); + } + + inline bool remove() const + { + return mOS.remove(mPathName); + } + + inline bool renameTo(std::string dest) + { + if (mOS.move(mPathName, dest)) + { + mPathName = dest; + return true; + } + return false; + } + + inline sys::Off_T length() const + { + return mOS.getSize(mPathName); + } + + inline void reset(std::string str) + { + mPathName = str; + } + +protected: + std::string mPathName; + OS mOS; +}; + +} + +std::ostream& operator<<(std::ostream& os, const sys::Path& path); +std::istream& operator>>(std::istream& os, sys::Path& path); + +#endif diff --git a/modules/c++/sys/include/sys/Process.h b/modules/c++/sys/include/sys/Process.h new file mode 100644 index 000000000..fc1695a6b --- /dev/null +++ b/modules/c++/sys/include/sys/Process.h @@ -0,0 +1,57 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __SYS_RUNTIME_PROCESS_H__ +#define __SYS_RUNTIME_PROCESS_H__ + + +/*! + * \file + * \brief Runtime, system-independent process creation API + * + * When it comes to multitasking, we almost all prefer threads to + * heritage process calls. However, threads and processes are almost + * never equivalent. Sometimes we need a process. Here we define + * a simple API for process creation in a system-independent manner + * + */ + +#include "sys/ProcessInterface.h" + +#if defined(WIN32) +# include "sys/ProcessWin32.h" +namespace sys +{ +typedef ProcessWin32 Process; +} +# +#else +# include "sys/ProcessUnix.h" +namespace sys +{ +typedef ProcessUnix Process; +} +#endif + + +#endif diff --git a/modules/c++/sys/include/sys/ProcessInterface.h b/modules/c++/sys/include/sys/ProcessInterface.h new file mode 100644 index 000000000..92a1d44d6 --- /dev/null +++ b/modules/c++/sys/include/sys/ProcessInterface.h @@ -0,0 +1,71 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __SYS_RUNTIME_PROCESS_INTERFACE_H__ +#define __SYS_RUNTIME_PROCESS_INTERFACE_H__ + + +/*! + * \file + * \brief Runtime, system-independent process creation API + * + * When it comes to multitasking, we almost all prefer threads to + * heritage process calls. However, threads and processes are almost + * never equivalent. Sometimes we need a process. Here we define + * a simple API for process creation in a system-independent manner + * + */ + +#include "sys/Dbg.h" +#include "sys/Runnable.h" +#include + +namespace sys +{ + +template class ProcessInterface : public sys::Runnable +{ +public: + enum { THE_CHILD = 0 }; + enum { PROCESS_CREATE_FAILED = -1 }; + ProcessInterface() + { + mTarget = this; + } + ProcessInterface(sys::Runnable* target) : mTarget(target) + {} + + virtual ~ProcessInterface() + {} + + virtual void start() = 0; + virtual void waitFor() = 0; + virtual void run() = 0; + +protected: + Pid_T mChildProcessID; + sys::Runnable* mTarget; +}; +} + +#endif diff --git a/modules/c++/sys/include/sys/ProcessUnix.h b/modules/c++/sys/include/sys/ProcessUnix.h new file mode 100644 index 000000000..2db268751 --- /dev/null +++ b/modules/c++/sys/include/sys/ProcessUnix.h @@ -0,0 +1,68 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __SYS_PROCESS_UNIX_H__ +#define __SYS_PROCESS_UNIX_H__ + + +#if defined(__GNUC__) +# if defined(__sgi) || defined(__sgi__) +# ifdef _FIX_BROKEN_HEADERS + typedef long long __int64_t; + typedef __int64_t jid_t; +# endif +# endif +#endif + +#if !defined(WIN32) + +#include +#include +#include +#include +#include +#include +#include +#include "sys/Conf.h" +#include "sys/ProcessInterface.h" + + +namespace sys +{ +class ProcessUnix : public ProcessInterface< Pid_T > +{ +public: + ProcessUnix() + {} + ProcessUnix(Runnable* target): ProcessInterface< Pid_T >(target) + {} + virtual ~ProcessUnix() + {} + void start(); + void waitFor(); +}; +} + + +#endif +#endif diff --git a/modules/c++/sys/include/sys/ProcessWin32.h b/modules/c++/sys/include/sys/ProcessWin32.h new file mode 100644 index 000000000..1d6e21440 --- /dev/null +++ b/modules/c++/sys/include/sys/ProcessWin32.h @@ -0,0 +1,51 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __SYS_PROCESS_WIN32_H__ +#define __SYS_PROCESS_WIN32_H__ + +#if defined(WIN32) + +#include "sys/ProcessInterface.h" +#include "sys/Thread.h" + +namespace sys +{ +class ProcessWin32 : public ProcessInterface< Thread* > +{ +public: + ProcessWin32() + {} + ProcessWin32(Runnable* target) : ProcessInterface< Thread* >(target) + {} + virtual ~ProcessWin32() + { + delete mChildProcessID; + } + void start(); + void waitFor(); +}; + +} +#endif +#endif diff --git a/modules/c++/sys/include/sys/ReadWriteMutex.h b/modules/c++/sys/include/sys/ReadWriteMutex.h new file mode 100644 index 000000000..654ca917b --- /dev/null +++ b/modules/c++/sys/include/sys/ReadWriteMutex.h @@ -0,0 +1,91 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __SYS_READ_WRITE_MUTEX_INTERFACE_H__ +#define __SYS_READ_WRITE_MUTEX_INTERFACE_H__ + + + +#if defined(_REENTRANT) && !defined(__APPLE_CC__) + +#include "sys/Dbg.h" +#include "sys/Mutex.h" +#include "sys/Semaphore.h" + +namespace sys +{ + + /*! + * \class ReadWriteMutex + * \brief Locks resources exclusively during writes while allowing + * simultaneous reads + * + */ + class ReadWriteMutex + { + public: + //! Constructor + ReadWriteMutex(int maxReaders) : mSem(maxReaders) + { + mMaxReaders = maxReaders; + dbg_printf("Creating a read/write mutex\n"); + } + + //! Destructor + virtual ~ReadWriteMutex() + { + dbg_printf("Destroying a read/write mutex\n"); + } + + /*! + * Lock for reading (no writes allowed) + */ + virtual void lockRead(); + + /*! + * Unlock for reading (writes allowed) + */ + virtual void unlockRead(); + + /*! + * Lock for writing (no reads/other writes allowed) + */ + virtual void lockWrite(); + + /*! + * Unlock for writing (reads allowed) + */ + virtual void unlockWrite(); + + protected: + sys::Semaphore mSem; + sys::Mutex mMutex; + int mMaxReaders; + }; + +} + +#endif // Are we reentrant? + +#endif + diff --git a/modules/c++/sys/include/sys/Runnable.h b/modules/c++/sys/include/sys/Runnable.h new file mode 100644 index 000000000..ae7a9987d --- /dev/null +++ b/modules/c++/sys/include/sys/Runnable.h @@ -0,0 +1,64 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __SYS_RUNNABLE_H__ +#define __SYS_RUNNABLE_H__ + + +namespace sys +{ +/*! + * \class Runnable + * \brief Defines interface for runnables + * + * This class defines the interface for action objects + * If you need an object that runs in its own space + * you should inherit this class. You may ONLY assign + * dynamically allocated runnables to this class, because + * auto-deletion is done. + * + * The intention of the Runnable is that it behave identically + * to the java Runnable class. Runnable implements the Command + * Design Pattern. + * + */ +class Runnable +{ +public: + /*! Constructor */ + Runnable() + {} + + //! Destructor + virtual ~Runnable() + {} + + /*! + * Overload this function in order with an action to make + * this object runnable. + */ + virtual void run() = 0; +}; +} + +#endif diff --git a/modules/c++/sys/include/sys/Semaphore.h b/modules/c++/sys/include/sys/Semaphore.h new file mode 100644 index 000000000..7928cfa72 --- /dev/null +++ b/modules/c++/sys/include/sys/Semaphore.h @@ -0,0 +1,81 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __SYS_SEMAPHORE_H__ +#define __SYS_SEMAPHORE_H__ +/** + * \file + * \brief Include the right semaphore. + * + * This file will auto-select the semaphore of choice, + * if one is to be defined. + * \note We need to change the windows part to check _MT + * because that is how it determines reentrance! + * + */ +# if defined(_REENTRANT) + +# if defined(USE_NSPR_THREADS) +# include "sys/SemaphoreNSPR.h" +namespace sys +{ +typedef SemaphoreNSPR Semaphore; +} +// If they explicitly want posix +# elif defined(__POSIX) && !defined(__APPLE_CC__) +# include "sys/SemaphorePosix.h" +namespace sys +{ +typedef SemaphorePosix Semaphore; +} +# elif defined(WIN32) +# include "sys/SemaphoreWin32.h" +namespace sys +{ +typedef SemaphoreWin32 Semaphore; +} +# elif defined(__sun) && !defined(__POSIX) +# include "sys/SemaphoreSolaris.h" +namespace sys +{ +typedef SemaphoreSolaris Semaphore; +} +# elif defined(__sgi) && !defined(__POSIX) +# include "sys/SemaphoreIrix.h" +namespace sys +{ +typedef SemaphoreIrix Semaphore; +} +# elif defined(__APPLE_CC__) +typedef int Semaphore; +# else +# include "sys/SemaphorePosix.h" +namespace sys +{ +typedef SemaphorePosix Semaphore; +} +# endif // Which thread package? + +# endif // Are we reentrant? + +#endif // End of header diff --git a/modules/c++/sys/include/sys/SemaphoreInterface.h b/modules/c++/sys/include/sys/SemaphoreInterface.h new file mode 100644 index 000000000..d43e4d07c --- /dev/null +++ b/modules/c++/sys/include/sys/SemaphoreInterface.h @@ -0,0 +1,53 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __SYS_SEMAPHORE_INTERFACE_H__ +#define __SYS_SEMAPHORE_INTERFACE_H__ + +# if defined(_REENTRANT) +#include +#include "sys/SystemException.h" + +namespace sys +{ +class SemaphoreInterface +{ + +public: + + SemaphoreInterface() + {} + + virtual ~SemaphoreInterface() + {} + + virtual void signal() = 0; + + virtual void wait() = 0; + +}; + +} + +# endif +#endif diff --git a/modules/c++/sys/include/sys/SemaphoreIrix.h b/modules/c++/sys/include/sys/SemaphoreIrix.h new file mode 100644 index 000000000..9725ac261 --- /dev/null +++ b/modules/c++/sys/include/sys/SemaphoreIrix.h @@ -0,0 +1,56 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __SYS_SEMAPHORE_IRIX_H__ +#define __SYS_SEMAPHORE_IRIX_H__ + +#if defined(__sgi) && defined(_REENTRANT) && !defined(__POSIX) + +#include +#include "sys/SyncFactoryIrix.h" +#include "sys/SemaphoreInterface.h" + +namespace sys +{ +class SemaphoreIrix : public SemaphoreInterface +{ +public: + SemaphoreIrix(unsigned int count = 0); + virtual ~SemaphoreIrix(); + void wait(); + void signal(); + usema_t*& getNative(); + + /*! + * Return the type name. This function is essentially free, + * because it is static RTTI. + */ + const char* getNativeType() const + { + return typeid(mNative).name(); + } +}; +} + +#endif +#endif diff --git a/modules/c++/sys/include/sys/SemaphoreNSPR.h b/modules/c++/sys/include/sys/SemaphoreNSPR.h new file mode 100644 index 000000000..61ad25598 --- /dev/null +++ b/modules/c++/sys/include/sys/SemaphoreNSPR.h @@ -0,0 +1,56 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __SYS_SEMAPHORE_NSPR_H__ +#define __SYS_SEMAPHORE_NSPR_H__ + +#if defined(USE_NSPR_THREADS) && defined(_REENTRANT) + +#include "except/Exception.h" + +#include "sys/SemaphoreInterface.h" +#include + +namespace sys +{ +class SemaphoreNSPR : public SemaphoreInterface +{ +public: + SemaphoreNSPR(unsigned count = 0) + { + throw except::Exception("NSPR Does not use semaphores."); + } + ~SemaphoreNSPR() + {} + + void wait() + {} + + void signal() + {} + +}; +} + +#endif +#endif diff --git a/modules/c++/sys/include/sys/SemaphorePosix.h b/modules/c++/sys/include/sys/SemaphorePosix.h new file mode 100644 index 000000000..c02889697 --- /dev/null +++ b/modules/c++/sys/include/sys/SemaphorePosix.h @@ -0,0 +1,62 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __SYS_SEMAPHORE_POSIX_H__ +#define __SYS_SEMAPHORE_POSIX_H__ +#if defined(__POSIX) && defined(_REENTRANT) && !defined(__APPLE_CC__) + +#include "sys/SemaphoreInterface.h" + +#if defined(__APPLE_CC_H__) +# include +#else +# include +#endif + +namespace sys +{ +// typedef ::sem_t sem_t; +class SemaphorePosix : public SemaphoreInterface +{ +public: + SemaphorePosix(unsigned int count = 0); + virtual ~SemaphorePosix(); + void wait(); + void signal(); + sem_t& getNative(); + + /*! + * Return the type name. This function is essentially free, + * because it is static RTTI. + */ + const char* getNativeType() const + { + return typeid(mNative).name(); + } +private: + sem_t mNative; +}; +} + +#endif +#endif diff --git a/modules/c++/sys/include/sys/SemaphoreSolaris.h b/modules/c++/sys/include/sys/SemaphoreSolaris.h new file mode 100644 index 000000000..4a17289d6 --- /dev/null +++ b/modules/c++/sys/include/sys/SemaphoreSolaris.h @@ -0,0 +1,56 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __SYS_SEMAPHORE_POSIX_H__ +#define __SYS_SEMAPHORE_POSIX_H__ + +#if defined(__sun) && defined(_REENTRANT) && !defined(__POSIX) +#include +#include "sys/SemaphoreInterface.h" + +namespace sys +{ +class SemaphoreSolaris : public SemaphoreInterface +{ +public: + SemaphoreSolaris(unsigned int count = 0); + virtual ~SemaphoreSolaris(); + void wait(); + void signal(); + sema_t& getNative(); + + /*! + * Return the type name. This function is essentially free, + * because it is static RTTI. + */ + const char* getNativeType() const + { + return typeid(mNative).name(); + } +private: + sema_t mNative; +}; +} + +#endif +#endif diff --git a/modules/c++/sys/include/sys/SemaphoreWin32.h b/modules/c++/sys/include/sys/SemaphoreWin32.h new file mode 100644 index 000000000..87634832c --- /dev/null +++ b/modules/c++/sys/include/sys/SemaphoreWin32.h @@ -0,0 +1,67 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __SYS_SEMAPHORE_WIN32_H__ +#define __SYS_SEMAPHORE_WIN32_H__ + +#if defined(WIN32) && defined(_REENTRANT) + +#if !defined(USE_NSPR_THREADS) && !defined(__POSIX) + +#include "sys/Conf.h" +#include "sys/SemaphoreInterface.h" + +namespace sys +{ + +class SemaphoreWin32 : public SemaphoreInterface +{ +public: + enum { MAX_COUNT = 10 }; + SemaphoreWin32(unsigned int count = 0); + + virtual ~SemaphoreWin32() + {} + + void wait(); + + void signal(); + + HANDLE& getNative(); + + /*! + * Return the type name. This function is essentially free, + * because it is static RTTI. + */ + const char* getNativeType() const + { + return typeid(mNative).name(); + } +private: + HANDLE mNative; +}; + +} +#endif +#endif +#endif diff --git a/modules/c++/sys/include/sys/StopWatch.h b/modules/c++/sys/include/sys/StopWatch.h new file mode 100644 index 000000000..051a76255 --- /dev/null +++ b/modules/c++/sys/include/sys/StopWatch.h @@ -0,0 +1,103 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __SYS_STOPWATCH_H__ +#define __SYS_STOPWATCH_H__ + +#include "sys/LocalDateTime.h" + +namespace sys +{ + +class StopWatch +{ +public: + StopWatch(){} + virtual ~StopWatch(){} + /*! + * Start the timer and return the time in millis + */ + virtual double start() = 0; + + /*! + * Stop the timer and return the elapsed time in millis + */ + virtual double stop() = 0; + + /*! + * Pause the timer and return the elapsed time in millis + */ + virtual double pause() = 0; + + /*! + * Clear the timer + */ + virtual void clear() = 0; +}; + +class RealTimeStopWatch : public StopWatch +{ +protected: + double mStartTime; + double mTimePaused; + double mPauseStartTime; + bool mPaused; +public: + RealTimeStopWatch(); + + ~RealTimeStopWatch(); + + double start(); + + double stop(); + + double pause(); + + void clear(); +}; + +class CPUStopWatch : public StopWatch +{ +protected: + clock_t mStartTime; + clock_t mPauseStartTime; + clock_t mTimePaused; + bool mPaused; + double mClocksPerMillis; +public: + CPUStopWatch(); + + ~CPUStopWatch(); + + double start(); + + double stop(); + + double pause(); + + void clear(); +}; + +} + +#endif diff --git a/modules/c++/sys/include/sys/SyncFactoryIrix.h b/modules/c++/sys/include/sys/SyncFactoryIrix.h new file mode 100644 index 000000000..0ba2638a1 --- /dev/null +++ b/modules/c++/sys/include/sys/SyncFactoryIrix.h @@ -0,0 +1,220 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __SYS_SYNC_FACTORY_IRIX_H__ +#define __SYS_SYNC_FACTORY_IRIX_H__ + +# if defined(__sgi) && defined(_REENTRANT) && !defined(__POSIX) +#include +#include "sys/Dbg.h" +#include +#include +#include +#include +#include +#include +#include +#include + +namespace sys +{ +class SemaphoreIrix; +class MutexIrix; +class ThreadIrix; +class ConditionVarIrix; + + +class SyncInterface +{ +public: + SyncInterface() + {} + + virtual ~SyncInterface() + {} + + virtual bool waitSemaphore(SemaphoreIrix& sema) = 0; + + virtual bool signalSemaphore(SemaphoreIrix& sema) = 0; + + virtual bool setLock(MutexIrix& mutex) = 0; + virtual bool unsetLock(MutexIrix& mutex) = 0; + virtual bool startThread(ThreadIrix& t) = 0; + virtual bool killThread(ThreadIrix& t) = 0; + virtual bool createLock(MutexIrix& mutex) = 0; + virtual bool destroyLock(MutexIrix& mutex) = 0; + virtual bool createSemaphore(SemaphoreIrix& sema, + unsigned int count) = 0; + virtual bool destroySemaphore(SemaphoreIrix& sema) = 0; + +}; + +class SyncFactoryIrix : public SyncInterface +{ +protected: +class SyncImplIrix : public SyncInterface + { + public: + SyncImplIrix(); + + virtual ~SyncImplIrix(); + + bool createLock(MutexIrix& mutex); + + bool destroyLock(MutexIrix& mutex); + + bool setLock(MutexIrix& mutex); + + bool unsetLock(MutexIrix& mutex); + + bool waitSemaphore(SemaphoreIrix& sema); + + bool signalSemaphore(SemaphoreIrix& sema); + + bool createSemaphore(SemaphoreIrix& sema, unsigned int count); + + bool destroySemaphore(SemaphoreIrix& sema); + + bool startThread(ThreadIrix& t); + + bool killThread(ThreadIrix& t); + + usptr_t* getArena() + { + return mArena; + } + int mRef; + + private: + usptr_t* mArena; + ulock_t* mGuard; + }; + + static std::auto_ptr cs; + static SyncFactoryIrix::SyncImplIrix* createImpl() + { + + if (!mImpl) + { + dbg_ln("Creating Impl"); + mImpl = new SyncFactoryIrix::SyncImplIrix(); + + } + return mImpl; + } + static void destroyImpl() + { + + if (mImpl != NULL) + { + dbg_ln("Destroying Impl"); + delete mImpl; + mImpl = NULL; + } + + } + +private: + + static SyncImplIrix* mImpl; +public: + SyncFactoryIrix() + {} + + ~SyncFactoryIrix() + { + // Deletes lock as well + if (mImpl->mRef == 0) + { + dbg_ln("There are no more references to the implementation. Deleting..."); + destroyImpl(); + } + } + + bool startThread(ThreadIrix& t) + { + EVAL(&t); + return createImpl()->startThread(t); + } + + bool killThread(ThreadIrix& t) + { + return createImpl()->killThread(t); + } + // SyncFactoryIrix().createLock(mutex); + // SyncFactoryIrix().destroyLock(mutex); + bool createLock(MutexIrix& mutex) + { + return createImpl()->createLock(mutex); + } + + bool destroyLock(MutexIrix& mutex) + { + + return createImpl()->destroyLock(mutex); + } + + bool waitSemaphore(SemaphoreIrix& sema) + { + return createImpl()->waitSemaphore(sema); + } + + bool signalSemaphore(SemaphoreIrix& sema) + { + return createImpl()->signalSemaphore(sema); + } + + bool setLock(MutexIrix& mutex) + { + return createImpl()->setLock(mutex); + } + bool unsetLock(MutexIrix& mutex) + { + return createImpl()->unsetLock(mutex); + } + + + bool createSemaphore(SemaphoreIrix& sema, unsigned int count) + { + // This functions 1) Locks (mULock) + // 2) Acts + // 3) Increments mRef + // 4) Unlocks + return createImpl()->createSemaphore(sema, count); + } + + + bool destroySemaphore(SemaphoreIrix& sema) + { + // This functions 1) Locks + // 2) Acts + // 3) Decrements mRef + // 4) Unlocks + return createImpl()->destroySemaphore(sema); + //if (mImpl->mRef == 0) delete mImpl; + + } +}; +} +# endif +#endif diff --git a/modules/c++/sys/include/sys/SystemException.h b/modules/c++/sys/include/sys/SystemException.h new file mode 100644 index 000000000..fd198cc16 --- /dev/null +++ b/modules/c++/sys/include/sys/SystemException.h @@ -0,0 +1,251 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __SYSTEM_EXCEPTION_H__ +#define __SYSTEM_EXCEPTION_H__ + +#include "sys/Err.h" +#include "except/Error.h" +#include "except/Exception.h" + +/*! + * \file SystemException.h + * \brief Provide system exceptions that are specialized for each OS + * + * This class makes use of the system-independent Err class to create + * system exceptions that leverage the OS-specific API for errors + */ +namespace sys +{ +/*! + * \class SystemException + * \brief An OS-independent exception class + */ +class SystemException : public except::Exception +{ +public: + + /*! + * Constructs the user message, and retrieves the last error. + * \param userMessage The user's message + */ + SystemException(const std::string& userMessage) : + except::Exception(userMessage) + { + Err e; + mMessage += std::string(": ") + e.toString(); + } + + /*! + * Constructs the user message, and retrieves the last error. + * \param c The user's context + */ + SystemException(const except::Context& c) : + except::Exception(c) + { + Err e; + mMessage += std::string(": ") + e.toString(); + } + + /*! + * Constructs the user message, and retrieves the last error. + * \param userMessage The user's message + */ + SystemException(const char *userMessage) : + except::Exception(userMessage) + { + Err e; + mMessage += std::string(": ") + e.toString(); + } + + /*! + * Constructs from the user message, AND the error + * \param userMessage A user's message + * \param errorId the system error id + */ + SystemException(const char *userMessage, int errorId): + except::Exception(userMessage) + { + Err e(errorId); + mMessage += std::string(": ") + e.toString(); + } + + /*! + * Constructs from the user message, AND the error + * \param userMessage A user's message + * \param errorId the system error id + */ + SystemException(const std::string& userMessage, int errorId) : + except::Exception(userMessage) + { + Err e(errorId); + mMessage += std::string(": ") + e.toString(); + } +}; + +/*! + * \class SystemError + * \brief Same as SystemException, but for an error + * + * This class is identical to SystemException, except that it is + * an error, not an exception + */ +class SystemError : public except::Error +{ +public: + + /*! + * Constructs the user message, and retrieves the last error. + * \param userMessage The user's message + */ + SystemError(const std::string& userMessage) : + except::Error(userMessage) + { + Err e; + mMessage += std::string(": ") + e.toString(); + } + + /*! + * Constructs the user message, and retrieves the last error. + * \param userMessage The user's message + */ + SystemError(const char *userMessage) : + except::Error(userMessage) + { + Err e; + mMessage += std::string(": ") + e.toString(); + } + + /*! + * Constructs from the user message, AND the error + * \param userMessage A user's message + * \param errorId the system error id + */ + SystemError(const char *userMessage, int errorId): + except::Error(userMessage) + { + Err e(errorId); + mMessage += std::string(": ") + e.toString(); + } + + /*! + * Constructs from the user message, AND the error + * \param userMessage A user's message + * \param errorId the system error id + */ + SystemError(const std::string& userMessage, int errorId) : + except::Error(userMessage) + { + Err e(errorId); + mMessage += std::string(": ") + e.toString(); + } + + /*! + * Constructs the user message, and retrieves the last error. + * \param c The user's context + */ + SystemError(const except::Context& c) : + except::Error(c) + { + Err e; + mMessage += std::string(": ") + e.toString(); + } +}; + + +/* class SocketException : public except::Exception */ +/* { */ +/* public: */ + + +/* SocketException(const std::string& userMessage) : */ +/* except::Exception(userMessage) */ +/* { */ +/* mErr = Err(); */ +/* } */ + + +/* SocketException(const char *userMessage) : */ +/* except::Exception(userMessage) {} */ + +/* SocketException(int errorId, */ +/* const char *userMessage) : */ +/* except::Exception(userMessage) */ +/* { */ +/* mErr = Err(errorId); */ +/* } */ + +/* SocketException(int errorId, */ +/* const char *userMessage) : */ +/* except::Exception(userMessage) */ +/* { */ +/* mErr = Err(errorId); */ +/* } */ + +/* Err& getErr() { return mErr; } */ +/* protected: */ +/* sys::Err mErr; */ +/* }; */ + +/* class SocketError : public except::Error */ +/* { */ +/* public: */ + +/* SocketError(const std::string& userMessage) : */ +/* except::Error(userMessage) */ +/* { */ +/* mErr = Err(); */ +/* } */ + + +/* SocketError(const char *userMessage) : */ +/* except::Error(userMessage) {} */ + +/* SocketError(int errorId, */ +/* const char *userMessage) : */ +/* except::Error(userMessage) */ +/* { */ +/* mErr = Err(errorId); */ +/* } */ + +/* SocketError(int errorId, */ +/* const char *userMessage) : */ +/* except::Error(userMessage) */ +/* { */ +/* mErr = Err(errorId); */ +/* } */ + +/* sys::Err& getErr() { return mErr; } */ + +/* protected: */ +/* sys::Err mErr; */ + +/* }; */ + + +// Temporary -- eventually want a socket error specific class +// so we can support winsock +typedef SystemException SocketException; +typedef SystemError SocketError; +} +#endif diff --git a/modules/c++/sys/include/sys/Thread.h b/modules/c++/sys/include/sys/Thread.h new file mode 100644 index 000000000..cc81eba6d --- /dev/null +++ b/modules/c++/sys/include/sys/Thread.h @@ -0,0 +1,82 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __SYS_THREAD_H__ +#define __SYS_THREAD_H__ + +/** + * \file + * \brief Include the right thread. + * + * This file will auto-select the thread of choice, + * if one is to be defined. + * \note We need to change the windows part to check _MT + * because that is how it determines reentrance! + * + */ +# if defined(_REENTRANT) + +// Netscape portable runtime +# if defined(USE_NSPR_THREADS) +# include "sys/ThreadNSPR.h" +namespace sys +{ +typedef ThreadNSPR Thread; +} +// If they explicitly want posix +# elif defined(__POSIX) +# include "sys/ThreadPosix.h" +namespace sys +{ +typedef ThreadPosix Thread; +} +# elif defined(WIN32) +# include "sys/ThreadWin32.h" +namespace sys +{ +typedef ThreadWin32 Thread; +} +# elif defined(__sun) && !defined(__POSIX) +# include "sys/ThreadSolaris.h" +namespace sys +{ +typedef ThreadSolaris Thread; +} +# elif defined(__sgi) && !defined(__POSIX) +# include "sys/ThreadIrix.h" +namespace sys +{ +typedef ThreadIrix Thread; +} +// If they havent defined anything and its !windows, we'll give 'em posix +# else +# include "sys/ThreadPosix.h" +namespace sys +{ +typedef ThreadPosix Thread; +} +# endif // Which thread package? + +# endif // Are we reentrant? + +#endif diff --git a/modules/c++/sys/include/sys/ThreadInterface.h b/modules/c++/sys/include/sys/ThreadInterface.h new file mode 100644 index 000000000..15c9e69a5 --- /dev/null +++ b/modules/c++/sys/include/sys/ThreadInterface.h @@ -0,0 +1,284 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __SYS_THREAD_INTERFACE_H__ +#define __SYS_THREAD_INTERFACE_H__ + +#include "sys/Runnable.h" + +#if defined(_REENTRANT) +#include +#include +#include "sys/SystemException.h" + + +namespace sys +{ +/*! + * \def STANDARD_START_CALL(MY_NAME, PTR_TO_ME) + * You should probably place this in you compatibility + * layer if you are writing a CTI integration package. + * call it as follows: + * + * \code + * static void* PthreadThread::start(void* v) + * { + * // declare this function. + * STANDARD_START_CALL(Win32Thread, v); + * return NULL; + * } + * \endcode + */ +#define STANDARD_START_CALL(MY_NAME, PTR_TO_ME) \ + sys::MY_NAME *me = \ + static_cast(PTR_TO_ME); \ + me->setIsRunning(true); \ + me->target()->run(); \ + me->setIsRunning(false); \ + + +/*! + * \class ThreadInterface + * \brief defines a thread, which implements a runnable + * \todo Add the string name variable and associate values + * + * A thread in java implements runnable, allowing it to pass + * threads as runners. The run part of the interface + * does nothing in the parent thread, however, if it is + * set to a thread, that thread's run function may be called + * + */ + +class ThreadInterface : public Runnable +{ +public: + enum { DEFAULT_LEVEL, KERNEL_LEVEL, USER_LEVEL }; + enum { MINIMUM_PRIORITY, NORMAL_PRIORITY, MAXIMUM_PRIORITY }; + + //! Default constructor + ThreadInterface() : mIsSelf(true) + { + initialize(this, NORMAL_PRIORITY, DEFAULT_LEVEL, ""); + } + /*! + * This, in C++, may seem redundant, since + * I can use the default constructor, but + * I want to be really obvious with this + * API + * \param name The name of this thread + */ + ThreadInterface(const std::string& name) : mIsSelf(true) + { + initialize(this, NORMAL_PRIORITY, DEFAULT_LEVEL, name); + } + + + /*! + * Constructor + * \param target What to run + */ + ThreadInterface(Runnable *target) : mIsSelf(false) + { + initialize(target, NORMAL_PRIORITY, DEFAULT_LEVEL, ""); + } + + /*! + * This, in C++, may seem redundant, since + * I can use the default constructor, but + * I want to be really obvious with this + * API + * \param target What to run + * \param name The name of this thread + */ + ThreadInterface(Runnable *target, + const std::string& name) : mIsSelf(false) + { + initialize(target, NORMAL_PRIORITY, DEFAULT_LEVEL, name); + } + + ThreadInterface(Runnable *target, + const std::string& name, + int level, + int priority) : mIsSelf(false) + { + initialize(target, priority, level, name); + } + + //! Destructor + virtual ~ThreadInterface() + { + // If the thread is still running, crash the program to prevent all kinds + // of nasty issues that could pop up (execution in freed memory, etc). + if (isRunning()) + { + std::cerr << Ctxt(FmtX("Thread object [%s] destructed before " \ + "thread terminated, aborting program.", + getName().c_str())) << std::endl; + abort(); + } + + if (mTarget && mTarget != this) + delete mTarget; + } + + /*! + * Return the name of this thread + * \return Thread name + */ + std::string getName() const + { + return mName; + } + + /*! + * Set the name of the thread + * \param name New name for thread + */ + void setName(const std::string& name) + { + mName = name; + } + + /*! + * Get the level at which this thread runs. + * DEFAULT_LEVEL means "I dont know or care" + * \return The level + */ + int getLevel() const + { + return mLevel; + } + + /*! + * Get the thread priority + * \return The thread priority + */ + int getPriority() const + { + return mPriority; + } + + /*! + * Set the thread priority. The meaning of this + * function depends upon the implementing thread packages. + * Please consult the notes individually for interpretations + * of the behavior. Setting the priority may take effect immediately, + * or it may not. Either way, the behavior should be graceful so + * as not to disturb the functionality of the actual thread. + * + * \param priority The new priority + */ + virtual void setPriority(int priority) + { + mPriority = priority; + } + + /*! + * Start the thread + * This function is called by the thread package user. + * + */ + virtual void start() = 0; + + /*! + * Destroy the thread + */ + virtual void kill() = 0; + + // You could say Thread(new MyThread()).start(); + /*! + * The only function that is specialized by the implementor + * This function is called by start if no target is defined, + * allowing the implementor to inherit this class directly + */ + virtual void run() + {} + + /*! + * Join the thread + */ + virtual void join() = 0; + + /*! + * Yield the current thread of control + */ + static void yield(); + // std::string toString() const { return mName; } + + /*! + * Return the target + * \return The target runnable + */ + Runnable* target() + { + return mTarget; + } + + bool isRunning() + { + return mIsRunning; + } + void setIsRunning(bool isRunning) + { + mIsRunning = isRunning; + } + +private: + bool mIsSelf; + + /*! + * Generic initialization routine for constructors + * to call. These arguments always need to be + * initialized + * + */ + void initialize(Runnable *target, + int priority, + int level, + const std::string& name) + { + mTarget = target; + mName = name; + mLevel = level; + mPriority = priority; + mIsRunning = false; + } + + //! The target (could be this) + Runnable *mTarget; + //! The name of this thread + std::string mName; + //! The priority of this thread + int mPriority; + //! The level at which this thread runs + int mLevel; + bool mIsRunning; + + // Noncopyable + ThreadInterface(const ThreadInterface& ); + const ThreadInterface& operator=(const ThreadInterface& ); +}; +} + +# endif +#endif diff --git a/modules/c++/sys/include/sys/ThreadIrix.h b/modules/c++/sys/include/sys/ThreadIrix.h new file mode 100644 index 000000000..8e7d00f0f --- /dev/null +++ b/modules/c++/sys/include/sys/ThreadIrix.h @@ -0,0 +1,139 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __SYS_THREAD_IRIX_H__ +#define __SYS_THREAD_IRIX_H__ + +#if defined(__sgi) && defined(_REENTRANT) && !defined(__POSIX) +#include "sys/SyncFactoryIrix.h" +#include "sys/ThreadInterface.h" +#include + +namespace sys +{ +inline long getThreadID() +{ + return (long)getpid(); +} + +class ThreadIrix : public ThreadInterface +{ +public: + + ThreadIrix(const std::string& name = "") : + ThreadInterface(name) + {} + + ThreadIrix(sys::Runnable *target, + const std::string& name = "") : + ThreadInterface(target, name) + {} + + ThreadIrix(sys::Runnable *target, + const std::string& name, + int level, + int priority) : + ThreadInterface(target, name, level, priority) + {} + + virtual ~ThreadIrix() + {} + + //virtual void start() + //{ + //SyncFactoryIrix::getInstance()->createThread(*this); + //void (*entry) (void *), unsigned inh, + /* mNative = sproc(start, */ + /* PR_SADDR|PR_SFDS|PR_SDIR|PR_SUMASK, */ + /* this); */ + /* if (mNative <= 0) */ + /* throw ThreadObjectException("ThreadIrix::start() failed"); */ + //} + + virtual void start() + { + dbg_printf("ThreadIrix::start()\n"); + if (!sys::SyncFactoryIrix().startThread(*this)) + throw sys::SystemException("start()"); + } + + virtual void kill() + { + dbg_printf("ThreadIrix::kill()\n"); + if (!sys::SyncFactoryIrix().killThread(*this)) + throw sys::SystemException("kill()"); + } + + static void __start(void *v) + { + EVAL(v); + dbg_printf("ThreadIrix::__start()\n"); + sys::ThreadIrix *me = (sys::ThreadIrix *)v; + me->target()->run(); + dbg_printf("ThreadIrix::__start() has completed\n"); + exit(EXIT_SUCCESS); + } + + //virtual bool kill() + //{ + //return SyncFactoryIrix->killThread(*this); + /* if ( ::kill(mNative, SIGKILL) == 0 ) { */ + /* mIsRunning = false; */ + /* return true; */ + /* } */ + /* return false; */ + //} + virtual void join(); + + static void yield(); + + /*! + * Returns the native type. You probably should not use this + * unless you have specific constraints on which package you use + * Use of this function may defeat the purpose of these classes: + * to provide thread implementation in an abstract interface. + */ + pid_t& getNative() + { + return mNative; + } + + /*! + * Return the type name. This function is essentially free, + * because it is static RTTI. + */ + const char* getNativeType() const + { + return typeid(mNative).name(); + } + +private: + pid_t mNative; +}; + + +} + +#endif +#endif + diff --git a/modules/c++/sys/include/sys/ThreadNSPR.h b/modules/c++/sys/include/sys/ThreadNSPR.h new file mode 100644 index 000000000..e3b4c73a7 --- /dev/null +++ b/modules/c++/sys/include/sys/ThreadNSPR.h @@ -0,0 +1,166 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __SYS_THREAD_NSPR_THREAD_H__ +#define __SYS_THREAD_NSPR_THREAD_H__ + +# if defined(USE_NSPR_THREADS) +#include "sys/ThreadInterface.h" +#include +#include +#include +#include + + +namespace sys +{ + + inline long getThreadID() + { + return (long) PR_GetCurrentThread(); + } + + +/*! + * \class ThreadNSPR + * \brief The implementation for Netscape Portable Runtime threads + * + * This class wraps the Netscape thread code. It can be used with + * default constructors, making it a user-level thread. It could + * also be called with a specialized derived class. The custom + * functions here allow for some non-standard manipulation (for + * example, the number of CPU's). Somebody put a lot of work into + * NSPR, and I didnt want to avoid some of the clever features, + * just because pthreads or Caspr dont support them + * + */ +class ThreadNSPR : public ThreadInterface +{ +public: + /*! + * The default constructor. When called with no args, + * produce a user-level local thread + * \param name Name of thread + * \param isLocal Set to true if you want local threads + */ + ThreadNSPR(const std::string& name = "", + bool isLocal = true) : + ThreadInterface(name) + { + mIsLocal = isLocal; + } + + /*! + * The alternate constructor. This binds a runnable. + * The second and third args are the same as in the default + * constructor. + * \param target What to run + * \param name Name of thread + * \param isLocal Set to true if you want local threads + */ + ThreadNSPR(Runnable *target, + const std::string& name = "", + bool isLocal = true) : + ThreadInterface(target, name) + { + mIsLocal = isLocal; + } + + ThreadNSPR(Runnable *target, + const std::string& name, + int level, + int priority, + bool isLocal = true) : + ThreadInterface(target, name, level, priority) + { + mIsLocal = isLocal; + } + //! The destructor + virtual ~ThreadNSPR() + {} + + /*! + * Start the thread running. Same as in other thread + * implementations + */ + virtual void start(); + + /*! + * The start function that is bound to the native create call + * This should not be used directly + * \param v The start arg + */ + static void __start(void *v); + + /*! + * The kill function. Killing doesnt work on NSPR threads. + * Please refer to + * http://www.mozilla.org/projects/nspr/tech-notes/abruptexit.html + * for more information + */ + virtual void kill() + { + throw sys::SystemException("kill() not implemented on NSPR"); + } + /*! + * Join the thread + * + */ + virtual void join(); + /*! + * Yield the thread. Calls PR_Sleep with an interval of + * PR_INTERVAL_NO_WAIT + * + */ + static void yield(); + + /*! + * Returns the native type. You probably should not use this + * unless you have specific constraints on which package you use + * Use of this function may defeat the purpose of these classes: + * to provide thread implementation in an abstract interface. + */ + PRThread *& getNative() + { + return mNative; + } + + /*! + * Return the type name. This function is essentially free, + * because it is static RTTI. + */ + const char* getNativeType() const + { + return typeid(mNative).name(); + } + +protected: + bool mIsLocal; +private: + PRThread * mNative; +}; +} + +# endif +#endif + diff --git a/modules/c++/sys/include/sys/ThreadPosix.h b/modules/c++/sys/include/sys/ThreadPosix.h new file mode 100644 index 000000000..8b3296d61 --- /dev/null +++ b/modules/c++/sys/include/sys/ThreadPosix.h @@ -0,0 +1,150 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __SYS_THREAD_PTHREAD_THREAD_H__ +#define __SYS_THREAD_PTHREAD_THREAD_H__ + +#if defined(__POSIX) && defined(_REENTRANT) + +#include +#include +#include "sys/ThreadInterface.h" + + +/*! + * \file ThreadPosix.h + * \brief Provides the compatibility layer for pthreads + * + * If linked properly, this library allows the developer to leverage upon + * the pthreads API using C++ objects. + */ +namespace sys +{ + + /*! + * Function returns a string identifier for the current + * thread. + */ + inline long getThreadID() + { + return (long)pthread_self(); + } + +/*! + * \class ThreadPosix + * \brief The implementation of a pthread-specialized thread + * + * This class provides the wrapper for a pthread_t. + * + */ +class ThreadPosix : public ThreadInterface +{ + +public: + /*! + * Default constructor. Allows ThreadInterface to bind this to target + * \param name The name + */ + ThreadPosix(const std::string& name = "") : + ThreadInterface(name) + {} + /*! + * Alternate constructor + * \param target What to run + * \param name The name + */ + ThreadPosix(Runnable *target, + const std::string& name = "") : + ThreadInterface(target, name) + {} + + + ThreadPosix(Runnable *target, + const std::string& name, + int level, + int priority) : + ThreadInterface(target, name, level, priority) + {} + + //! Destructor + virtual ~ThreadPosix() + {} + + /*! + * The startpoint for thread processing + */ + virtual void start(); + + + /*! + * Run function defined and bound to pthread_create. + * This should not be invoked directly + * \param v The start arg + */ + static void *__start(void *v); + + + /*! + * Calls the native destroy stuff + */ + virtual void kill(); + + /*! + * Join the pthread + */ + virtual void join(); + + /*! + * Calls sched_yield to yield the thread of control + */ + static void yield(); + + /*! + * Returns the native type. You probably should not use this + * unless you have specific constraints on which package you use + * Use of this function may defeat the purpose of these classes: + * to provide thread implementation in an abstract interface. + */ + pthread_t& getNative() + { + return mNative; + } + + /*! + * Return the type name. This function is essentially free, + * because it is static RTTI. + */ + const char* getNativeType() const + { + return typeid(mNative).name(); + } + +private: + pthread_t mNative; + +}; + +} + +#endif +#endif diff --git a/modules/c++/sys/include/sys/ThreadSolaris.h b/modules/c++/sys/include/sys/ThreadSolaris.h new file mode 100644 index 000000000..909560153 --- /dev/null +++ b/modules/c++/sys/include/sys/ThreadSolaris.h @@ -0,0 +1,135 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __SYS_THREAD_SOLARIS_THREAD_H__ +#define __SYS_THREAD_SOLARIS_THREAD_H__ + + +#if defined(__sun) && defined(_REENTRANT) && !defined(__POSIX) + +#include +#include +#include "sys/ThreadInterface.h" + +namespace sys +{ + + inline long getThreadID() + { + return (long)thr_self(); + } + +/*! + * \class ThreadSolaris + * \brief The implementation of a pthread-specialized thread + * + * This class provides the wrapper for a pthread_t. + * + */ +class ThreadSolaris : public ThreadInterface +{ +public: + + //! Default constructor. Allows ThreadInterface to bind this to target + ThreadSolaris(const std::string& name = "") : ThreadInterface(name) + {} + + /*! + * Alternate constructor + * \param target What to run + * \param name The name + */ + ThreadSolaris(Runnable *target, + const std::string& name = "") : + ThreadInterface(target, name) + {} + + ThreadSolaris(Runnable *target, + const std::string& name, + int level, + int priority) : + ThreadInterface(target, name, level, priority) + {} + + //! Destructor + virtual ~ThreadSolaris() + {} + + /*! + * The startpoint for thread processing + */ + virtual void start(); + + /*! + * Calls the native destroy stuff + */ + virtual void kill(); + + /*! + * Join the pthread + */ + virtual void join(); + + /*! + * Calls sched_yield to yield the thread of control + */ + static void yield(); + + /*! + * Returns the native type. You probably should not use this + * unless you have specific constraints on which package you use + * Use of this function may defeat the purpose of these classes: + * to provide thread implementation in an abstract interface. + */ + thread_t& getNative() + { + return mNative; + } + + /*! + * Return the type name. This function is essentially free, + * because it is static RTTI. + */ + const char* getNativeType() const + { + return typeid(mNative).name(); + } + +private: + thread_t mNative; +}; + +} + +extern "C" +{ + /*! + * Run function defined and bound to pthread_create. + * This should not be invoked directly + * \param v The start arg + */ + void *__sys_ThreadSolaris_start(void *v); + +} +#endif +#endif diff --git a/modules/c++/sys/include/sys/ThreadWin32.h b/modules/c++/sys/include/sys/ThreadWin32.h new file mode 100644 index 000000000..d0bbe8a3b --- /dev/null +++ b/modules/c++/sys/include/sys/ThreadWin32.h @@ -0,0 +1,143 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __SYS_THREAD_WIN32_H__ +#define __SYS_THREAD_WIN32_H__ + +#if defined(WIN32) && defined(_REENTRANT) + +#if !defined(USE_NSPR_THREADS) && !defined(__POSIX) + +#include "sys/ThreadInterface.h" +#include "sys/Conf.h" +#include + + +#define sleep Sleep + +// A typedef and macro to make _beginthreadex look like CreateThread +// See MSDN Wind32 Q&A July 1999 by Jeffrey Richter +typedef unsigned (__stdcall *THREAD_START_FN) (void *); + +#if defined(USE_CREATETHREAD) +# define __CREATETHREAD(psa, cbStack, pfnStartAddr, \ + pvParam, fdwCreate, pdwThreadID) \ + CreateThread(psa, cbStack, \ + (LPTHREAD_START_ROUTINE)(pfnStartAddr), \ + (void*)pvParam, fdwCreate, \ + pdwThreadID) + +#else +# define __CREATETHREAD(psa, cbStack, pfnStartAddr, \ + pvParam, fdwCreate, pdwThreadID) \ + ((HANDLE) _beginthreadex( \ + (void *) (psa), \ + (unsigned) (cbStack), \ + (THREAD_START_FN) (pfnStartAddr), \ + (void *) (pvParam), \ + (unsigned) (fdwCreate), \ + (unsigned *) (pdwThreadID))) +#endif +namespace sys +{ + + + inline long getThreadID() + { + return (long)GetCurrentThreadId(); + } + +class ThreadWin32 : public ThreadInterface +{ +public: + + ThreadWin32(const std::string& name = "") : ThreadInterface(name) + {} + + ThreadWin32(sys::Runnable *target, + const std::string& name = "") : + ThreadInterface(target, name) + {} + + ThreadWin32(sys::Runnable *target, + const std::string& name, + int level, + int priority) : + ThreadInterface(target, name, level, priority) + {} + + + virtual ~ThreadWin32(); + virtual void start(); + static DWORD WINAPI __start(void *v) + { + STANDARD_START_CALL(ThreadWin32, v); + + return 0; + } + + //! Not implemented + virtual void kill() + { + throw sys::SystemException("kill() not implemented in ThreadWin32"); + } + virtual void join(); + static void yield() + { +#ifdef USING_WINNT + SwitchToThread(); +#else + throw sys::SystemException("Thread::yield() only supported in windows NT 4.0 or greater!"); +#endif + + } + + /*! + * Returns the native type. You probably should not use this + * unless you have specific constraints on which package you use + * Use of this function may defeat the purpose of these classes: + * to provide thread implementation in an abstract interface. + */ + HANDLE & getNative() + { + return mNative; + } + + /*! + * Return the type name. This function is essentially free, + * because it is static RTTI. + */ + const char* getNativeType() const + { + return typeid(mNative).name(); + } + +private: + HANDLE mNative; +}; + +} + +#endif // Not using other thread package +#endif // Is windows +#endif diff --git a/modules/c++/sys/include/sys/TimeStamp.h b/modules/c++/sys/include/sys/TimeStamp.h new file mode 100644 index 000000000..893299529 --- /dev/null +++ b/modules/c++/sys/include/sys/TimeStamp.h @@ -0,0 +1,103 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __SYS_TIME_STAMP_H__ +#define __SYS_TIME_STAMP_H__ + +#include +#include "str/Format.h" +#include "sys/Conf.h" +#include "sys/LocalDateTime.h" +#include "sys/UTCDateTime.h" + +/*! + * \file TimeStamp.h + * \brief Get a timestamp in a system-independent manner + * + * Provide the API for timestamps + */ + +namespace sys +{ +/*! + * \class TimeStamp + * \brief Class for timestamping + * + */ +class TimeStamp +{ +public: + //! The maximum length of a timestamp + enum { MAX_TIME_STAMP = 64 }; + + /*! + * Default constructor. + * \param is24HourTime Optional specifier for military time + */ + TimeStamp(bool is24HourTime = false) : m24HourTime(is24HourTime) + {} + //! Destructor + ~TimeStamp() + {} + + /*! + * Produces a local-time string timestamp + * \return local-time + */ + std::string local() const + { + sys::LocalDateTime dt; + return dt.format(getFormat()); + } + + /*! + * Produces a gmt string timestamp + * \return gmt + */ + std::string gmt() const + { + sys::UTCDateTime dt; + return dt.format(getFormat()); + } + +private: + /*! + * Sets up string in desired format + * \return The string format for printing + */ + const char* getFormat() const + { + if (m24HourTime) + { + return "%m/%d/%Y, %H:%M:%S"; + } + return "%m/%d/%Y, %I:%M:%S%p"; + } + + //! Military time??? + bool m24HourTime; +}; + +} + +#endif diff --git a/modules/c++/sys/include/sys/UTCDateTime.h b/modules/c++/sys/include/sys/UTCDateTime.h new file mode 100755 index 000000000..8c5057afe --- /dev/null +++ b/modules/c++/sys/include/sys/UTCDateTime.h @@ -0,0 +1,85 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2012, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __SYS_UTC_DATE_TIME_H__ +#define __SYS_UTC_DATE_TIME_H__ + +#include + +namespace sys +{ + +/*! + * Representation of a UTC date/time structure. + */ +class UTCDateTime : public DateTime +{ +protected: + /** + * @brief Set the millis value from the members + */ + virtual void toMillis(); + + //! Given seconds since the epoch, provides the UTC time + virtual void getTime(time_t numSecondsSinceEpoch, tm& t) const; + +public: + static const char DEFAULT_DATETIME_FORMAT[]; + + /*! + * Construct as current date and time (UTC). + */ + UTCDateTime(); + + /*! + * Construct with time values. Date will be today. + */ + UTCDateTime(int hour, int minute, double second); + /*! + * Construct with date values. Time will be 00:00:00. + */ + UTCDateTime(int year, int month, int day); + /*! + * Construct with date and time values. + */ + UTCDateTime(int year, int month, int day, + int hour, int minute, double second); + /*! + * Construct with time in milliseconds. + */ + UTCDateTime(double timeInMillis); + + // unhide in the base class format method + using DateTime::format; + + /*! + * The default formatting looks like this: + * %Y-%m-%dT%H:%M:%SZ + * 2011-10-19T11:59:46Z + */ + std::string format() const; + +}; + +} + +#endif//__SYS_UTC_DATE_TIME_H__ diff --git a/modules/c++/sys/include/sys/config.h b/modules/c++/sys/include/sys/config.h new file mode 100644 index 000000000..02a93a908 --- /dev/null +++ b/modules/c++/sys/include/sys/config.h @@ -0,0 +1,137 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +/* include/sys/config.h. Generated by configure. */ +/* include/sys/config.h.in. Generated from configure.in by autoheader. */ + +/* Define to 1 if using `getloadavg.c'. */ +/* #undef C_GETLOADAVG */ + +/* Define to 1 for DGUX with . */ +/* #undef DGUX */ + +/* Define to 1 if the `getloadavg' function needs to be run setuid or setgid. + */ +/* #undef GETLOADAVG_PRIVILEGED */ + +/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ +/* #undef HAVE_DOPRNT */ + +/* Define to 1 if you have the `getloadavg' function. */ +/* #undef HAVE_GETLOADAVG */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_INTTYPES_H */ + +/* Define to 1 if you have the `' library (-l). */ +/* #undef HAVE_LIB */ + +/* Define to 1 if you have the `dgc' library (-ldgc). */ +/* #undef HAVE_LIBDGC */ + +/* Define to 1 if you have the `kstat' library (-lkstat). */ +/* #undef HAVE_LIBKSTAT */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_MACH_MACH_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_MEMORY_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_NLIST_H */ + +/* Define to 1 if you have the `pstat_getdynamic' function. */ +/* #undef HAVE_PSTAT_GETDYNAMIC */ + +/* Define to 1 if you have the `setlocale' function. */ +/* #undef HAVE_SETLOCALE */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_STDINT_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_STDLIB_H */ + +/* Define to 1 if you have the `strftime' function. */ +/* #undef HAVE_STRFTIME */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_STRINGS_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_STRING_H */ + +/* Define to 1 if `n_un.n_name' is member of `struct nlist'. */ +/* #undef HAVE_STRUCT_NLIST_N_UN_N_NAME */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_STAT_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_TYPES_H */ + +/* Define to 1 if you have that is POSIX.1 compatible. */ +/* #undef HAVE_SYS_WAIT_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_UNISTD_H */ + +/* Define to 1 if you have the `vprintf' function. */ +/* #undef HAVE_VPRINTF */ + +/* Define to 1 if your `struct nlist' has an `n_un' member. Obsolete, depend + on `HAVE_STRUCT_NLIST_N_UN_N_NAME */ +/* #undef NLIST_NAME_UNION */ + +/* Define to the address where bug reports for this package should be sent. */ +/* #undef PACKAGE_BUGREPORT */ + +/* Define to the full name of this package. */ +/* #undef PACKAGE_NAME */ + +/* Define to the full name and version of this package. */ +/* #undef PACKAGE_STRING */ + +/* Define to the one symbol short name of this package. */ +/* #undef PACKAGE_TARNAME */ + +/* Define to the version of this package. */ +/* #undef PACKAGE_VERSION */ + +/* The size of a `', as computed by sizeof. */ +/* #undef SIZEOF_ */ + +/* Define to 1 if you have the ANSI C header files. */ +/* #undef STDC_HEADERS */ + +/* Define to 1 on System V Release 4. */ +/* #undef SVR4 */ + +/* Define to 1 for Encore UMAX. */ +/* #undef UMAX */ + +/* Define to 1 for Encore UMAX 4.3 that has instead of + . */ +/* #undef UMAX4_3 */ + diff --git a/modules/c++/sys/include/sys/config.h.in b/modules/c++/sys/include/sys/config.h.in new file mode 100644 index 000000000..c3eea857c --- /dev/null +++ b/modules/c++/sys/include/sys/config.h.in @@ -0,0 +1,113 @@ +/* include/sys/config.h.in. Generated from configure.in by autoheader. */ + +/* Define to 1 if using `getloadavg.c'. */ +#undef C_GETLOADAVG + +/* Define to 1 for DGUX with . */ +#undef DGUX + +/* Define to 1 if the `getloadavg' function needs to be run setuid or setgid. + */ +#undef GETLOADAVG_PRIVILEGED + +/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ +#undef HAVE_DOPRNT + +/* Define to 1 if you have the `getloadavg' function. */ +#undef HAVE_GETLOADAVG + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the `' library (-l). */ +#undef HAVE_LIB + +/* Define to 1 if you have the `dgc' library (-ldgc). */ +#undef HAVE_LIBDGC + +/* Define to 1 if you have the `kstat' library (-lkstat). */ +#undef HAVE_LIBKSTAT + +/* Define to 1 if you have the header file. */ +#undef HAVE_MACH_MACH_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NLIST_H + +/* Define to 1 if you have the `pstat_getdynamic' function. */ +#undef HAVE_PSTAT_GETDYNAMIC + +/* Define to 1 if you have the `setlocale' function. */ +#undef HAVE_SETLOCALE + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the `strftime' function. */ +#undef HAVE_STRFTIME + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if `n_un.n_name' is member of `struct nlist'. */ +#undef HAVE_STRUCT_NLIST_N_UN_N_NAME + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have that is POSIX.1 compatible. */ +#undef HAVE_SYS_WAIT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to 1 if you have the `vprintf' function. */ +#undef HAVE_VPRINTF + +/* Define to 1 if your `struct nlist' has an `n_un' member. Obsolete, depend + on `HAVE_STRUCT_NLIST_N_UN_N_NAME */ +#undef NLIST_NAME_UNION + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* The size of a `', as computed by sizeof. */ +#undef SIZEOF_ + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Define to 1 on System V Release 4. */ +#undef SVR4 + +/* Define to 1 for Encore UMAX. */ +#undef UMAX + +/* Define to 1 for Encore UMAX 4.3 that has instead of + . */ +#undef UMAX4_3 + diff --git a/modules/c++/sys/source/AbstractOS.cpp b/modules/c++/sys/source/AbstractOS.cpp new file mode 100644 index 000000000..f5813b96e --- /dev/null +++ b/modules/c++/sys/source/AbstractOS.cpp @@ -0,0 +1,95 @@ +#include +#include +#include + +namespace sys +{ +AbstractOS::AbstractOS() +{ +} + +AbstractOS::~AbstractOS() +{ +} + +std::vector +AbstractOS::search(const std::vector& searchPaths, + const std::string& fragment, + const std::string& extension, + bool recursive) const +{ + std::vector elementsFound; + + // add the search criteria + if (!fragment.empty() && !extension.empty()) + { + sys::ExtensionPredicate extPred(extension); + sys::FragmentPredicate fragPred(fragment); + + sys::LogicalPredicate logicPred(false); + logicPred.addPredicate(&extPred); + logicPred.addPredicate(&fragPred); + + elementsFound = sys::FileFinder::search(logicPred, + searchPaths, + recursive); + } + else if (!extension.empty()) + { + sys::ExtensionPredicate extPred(extension); + elementsFound = sys::FileFinder::search(extPred, + searchPaths, + recursive); + } + else if (!fragment.empty()) + { + sys::FragmentPredicate fragPred(fragment); + elementsFound = sys::FileFinder::search(fragPred, + searchPaths, + recursive); + } + return elementsFound; +} + +bool AbstractOS::remove(const std::string& path, bool recursive) const +{ + bool success = true; + + if (isDirectory(path)) + { + if (recursive) + { + // Iterate through each entry in the directory and remove it too + DirectoryEntry dirEntry(path); + for (DirectoryEntry::Iterator iter = dirEntry.begin(); + iter != dirEntry.end(); + ++iter) + { + const std::string filename(*iter); + if (filename != "." && filename != "..") + { + if (!remove(sys::Path::joinPaths(path, filename), true)) + { + success = false; + } + } + } + } + + // Directory should be empty, so remove it + if (!removeDirectory(path)) + { + success = false; + } + } + else + { + if (!removeFile(path)) + { + success = false; + } + } + + return success; +} +} diff --git a/modules/c++/sys/source/ConditionVarIrix.cpp b/modules/c++/sys/source/ConditionVarIrix.cpp new file mode 100644 index 000000000..2444955b7 --- /dev/null +++ b/modules/c++/sys/source/ConditionVarIrix.cpp @@ -0,0 +1,143 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#if defined(__sgi) && defined(_REENTRANT) && !defined(__POSIX) +#include "sys/ConditionVarIrix.h" + +#ifdef __SGI_LIBC_BEGIN_NAMESPACE_STD +using std::sigsend; +#endif + +sys::ConditionVarIrix::ConditionVarIrix() : + mMutexOwned(new sys::MutexIrix()), + mMutex(mMutexOwned.get()) +{ + dbg_ln("Creating a default condition variable"); +} + +sys::ConditionVarIrix::ConditionVarIrix(sys::MutexIrix *theLock, bool isOwner) : + mMutex(theLock) +{ + if (!theLock) + throw SystemException("ConditionVar received NULL mutex"); + + dbg_ln("Creating a cv given a mutex"); + if (isOwner) + mMutexOwned.reset(theLock); +} + +sys::ConditionVarIrix::~ConditionVarIrix() +{ + dbg_printf("BEGIN ~ConditionVarIrix\n"); + broadcast(); + mNative.clear(); + dbg_printf("END ~ConditionVarIrix\n"); +} + +void sys::ConditionVarIrix::acquireLock() +{ + mMutex->lock(); +} + +void sys::ConditionVarIrix::dropLock() +{ + mMutex->unlock(); +} + +void sys::ConditionVarIrix::signal() +{ + dbg_printf("ConditionVarIrix::signal()\n"); + int lStatus = 0; + if ( mNative.size() > 0 ) + { + lStatus = sigsend(P_PID, mNative.back(), SIGUSR1); + mNative.pop_back(); + } + if (lStatus != 0) + throw sys::SystemException("Condition Variable signal failed"); +} + +void sys::ConditionVarIrix::wait() +{ + dbg_printf("ConditionVarIrix::wait()\n"); + sys::ConditionVarIrix::wait(0); +} + +void sys::ConditionVarIrix::wait(double timeout) +{ + dbg_printf("Timed waiting on condition [%f]\n", timeout); + sigset_t lSignalSet; + siginfo_t lSignalInfo; + timespec_t *lTimeout = NULL; + + mNative.insert(mNative.begin(), getpid()); + + sigemptyset(&lSignalSet); + sigaddset(&lSignalSet, SIGUSR1); + + if ( timeout > 0 ) + { + lTimeout = new timespec_t; + lTimeout->tv_sec = (int)timeout; + lTimeout->tv_nsec = (int)((timeout - (int)timeout) * 1e9); + } + + mMutex->unlock(); + sigtimedwait(&lSignalSet, &lSignalInfo, lTimeout); + mMutex->lock(); + + for (int i = mNative.size(); i > 0; i-- ) + { + if ( mNative.at(i - 1) == getpid() ) + { + mNative.erase(mNative.begin() + i - 1); + } + } + + if (lTimeout != NULL) + delete lTimeout; + + if (lSignalInfo.si_signo != SIGUSR1) + throw sys::SystemException("Condition Variable wait failed"); +} + +void sys::ConditionVarIrix::broadcast() +{ + dbg_printf("ConditionVarIrix::broadcast()\n"); + int lStatus = 0; + while (mNative.size() > 0 ) + { + lStatus |= sigsend(P_PID, mNative.back(), SIGUSR1); + mNative.pop_back(); + } + if (lStatus != 0) + throw sys::SystemException("Condition Variable broadcast failed"); +} + +std::vector& sys::ConditionVarIrix::getNative() +{ + return mNative; +} + +#endif + diff --git a/modules/c++/sys/source/ConditionVarNSPR.cpp b/modules/c++/sys/source/ConditionVarNSPR.cpp new file mode 100644 index 000000000..1cf5c9a61 --- /dev/null +++ b/modules/c++/sys/source/ConditionVarNSPR.cpp @@ -0,0 +1,97 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#if defined(USE_NSPR_THREADS) +#include "sys/ConditionVarNSPR.h" + +sys::ConditionVarNSPR::ConditionVarNSPR() : + mMutexOwned(new sys::MutexNSPR()), + mMutex(mMutexOwned.get()) +{ + mNative = PR_NewCondVar( (mMutex->getNative()) ); + if (mNative == NULL) + throw sys::SystemException("Condition Variable initialization failed"); +} + +sys::CondtionVarNSPR::ConditionVarNSPR(sys::MutexNSPR *theLock, bool isOwner) : + mMutex(theLock) +{ + if (!theLock) + throw SystemException("ConditionVar received NULL mutex"); + + if (isOwner) + mMutexOwned.reset(theLock); + + mNative = PR_NewCondVar( (mMutex->getNative()) ); + if (mNative == NULL) + throw sys::SystemException("Condition Variable initialization failed"); +} + +sys::ConditionVarNSPR::~ConditionVarNSPR() +{ + PR_DestroyCondVar(mNative); +} + +void sys::ConditionVarNSPR::acquireLock() +{ + mMutex->lock(); +} + +void sys::ConditionVarNSPR::dropLock() +{ + mMutex->unlock(); +} + +void sys::ConditionVarNSPR::signal() +{ + if (PR_NotifyCondVar(mNative) != PR_SUCCESS) + throw sys::SystemException("Condition Variable signal failed"); + +} + +void sys::ConditionVarNSPR::wait() +{ + if (PR_WaitCondVar(mNative, PR_INTERVAL_NO_WAIT) != PR_SUCCESS) + throw sys::SystemException("Condition Variable wait failed"); +} + +void sys::ConditionVarNSPR::wait(double seconds) +{ + double milli = seconds * 1000; + if (PR_WaitCondVar(mNative, PR_MillisecondsToInterval((PRUint32) milli)) != PR_SUCCESS) + throw sys::SystemException("Condition Variable wait failed"); +} + +void sys::ConditionVarNSPR::broadcast() +{ + if (PR_NotifyAllCondVar(mNative) != PR_SUCCESS) + throw sys::SystemException("Condition Variable broadcast failed"); +} + +PRCondVar*& sys::ConditionVarNSPR::getNative() +{ + return mNative; +} + +#endif + diff --git a/modules/c++/sys/source/ConditionVarPosix.cpp b/modules/c++/sys/source/ConditionVarPosix.cpp new file mode 100644 index 000000000..ffdc04b6d --- /dev/null +++ b/modules/c++/sys/source/ConditionVarPosix.cpp @@ -0,0 +1,109 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#if defined(__POSIX) && defined(_REENTRANT) +#include +#include "sys/ConditionVarPosix.h" + +sys::ConditionVarPosix::ConditionVarPosix() : + mMutexOwned(new sys::MutexPosix()), + mMutex(mMutexOwned.get()) +{ + if ( ::pthread_cond_init(&mNative, NULL) != 0) + throw SystemException("ConditionVar initialization failed"); +} + +sys::ConditionVarPosix::ConditionVarPosix(sys::MutexPosix* theLock, bool isOwner) : + mMutex(theLock) +{ + if (!theLock) + throw SystemException("ConditionVar received NULL mutex"); + + if (isOwner) + mMutexOwned.reset(theLock); + + if ( ::pthread_cond_init(&mNative, NULL) != 0) + throw SystemException("ConditionVar initialization failed"); +} + +sys::ConditionVarPosix::~ConditionVarPosix() +{ + ::pthread_cond_destroy(&mNative); +} + +void sys::ConditionVarPosix::acquireLock() +{ + mMutex->lock(); +} + +void sys::ConditionVarPosix::dropLock() +{ + mMutex->unlock(); +} + +void sys::ConditionVarPosix::signal() +{ + dbg_printf("Signaling condition\n"); + if (::pthread_cond_signal(&mNative) != 0) + throw sys::SystemException("ConditionVar signal failed"); +} + +void sys::ConditionVarPosix::wait() +{ + dbg_printf("Waiting on condition\n"); + if (::pthread_cond_wait(&mNative, &(mMutex->getNative())) != 0) + throw sys::SystemException("ConditionVar wait failed"); +} + +void sys::ConditionVarPosix::wait(double seconds) +{ + dbg_printf("Timed waiting on condition [%f]\n", seconds); + + if ( seconds > 0 ) + { + timespec tout; + tout.tv_sec = time(NULL) + (int)seconds; + tout.tv_nsec = (int)((seconds - (int)(seconds)) * 1e9); + if (::pthread_cond_timedwait(&mNative, + &(mMutex->getNative()), + &tout) != 0) + throw sys::SystemException("ConditionVar wait failed"); + } + else + wait(); +} + +void sys::ConditionVarPosix::broadcast() +{ + dbg_printf("Broadcasting condition\n"); + if (::pthread_cond_broadcast(&mNative) != 0) + throw sys::SystemException("ConditionVar broadcast failed"); +} + +pthread_cond_t& sys::ConditionVarPosix::getNative() +{ + return mNative; +} + +#endif + diff --git a/modules/c++/sys/source/ConditionVarSolaris.cpp b/modules/c++/sys/source/ConditionVarSolaris.cpp new file mode 100644 index 000000000..389826a3c --- /dev/null +++ b/modules/c++/sys/source/ConditionVarSolaris.cpp @@ -0,0 +1,109 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#if defined(__sun) && defined(_REENTRANT) && !defined(__POSIX) +#include +#include +#include "sys/ConditionVarSolaris.h" + +sys::ConditionVarSolaris::ConditionVarSolaris() : + mMutexOwned(new sys::MutexSolaris()), + mMutex(mMutexOwned.get()) +{ + if ( ::cond_init(&mNative, NULL, NULL) != 0) + throw sys::SystemException("ConditionVar initialization failed"); +} + +sys::ConditionVarSolaris::ConditionVarSolaris(sys::MutexSolaris* theLock, bool isOwner) : + mMutex(theLock) +{ + if (!theLock) + throw SystemException("ConditionVar received NULL mutex"); + + if (isOwner) + mMutexOwned.reset(theLock); + + if ( ::cond_init(&mNative, NULL, NULL) != 0) + throw sys::SystemException("ConditionVar initialization failed"); +} + +sys::ConditionVarSolaris::~ConditionVarSolaris() +{ + ::cond_destroy(&mNative); +} + +void sys::ConditionVarSolaris::acquireLock() +{ + mMutex->lock(); +} + +void sys::ConditionVarSolaris::dropLock() +{ + mMutex->unlock(); +} + +void sys::ConditionVarSolaris::signal() +{ + dbg_printf("Signaling condition\n"); + if (::cond_signal(&mNative) != 0) + throw sys::SystemException("ConditionVar signal failed"); +} + +void sys::ConditionVarSolaris::wait() +{ + dbg_printf("Waiting on condition\n"); + if (::cond_wait(&mNative, &(mMutex->getNative())) != 0) + throw sys::SystemException("ConditionVar wait failed"); +} + +void sys::ConditionVarSolaris::wait(double seconds) +{ + dbg_printf("Timed waiting on condition [%f]\n", seconds); + if ( seconds > 0 ) + { + timestruc_t tout; + tout.tv_sec = time(NULL) + (int)seconds; + tout.tv_nsec = (int)((seconds - (int)(seconds)) * 1e9); + if (::cond_timedwait(&mNative, + &(mMutex->getNative()), + &tout) != 0) + throw sys::SystemException("ConditionVar wait failed"); + } + else + wait(); +} + +void sys::ConditionVarSolaris::broadcast() +{ + dbg_printf("Broadcasting condition\n"); + if (::cond_broadcast(&mNative) != 0) + throw sys::SystemException("ConditionVar broadcast failed"); +} + +cond_t& sys::ConditionVarSolaris::getNative() +{ + return mNative; +} + +#endif + diff --git a/modules/c++/sys/source/ConditionVarWin32.cpp b/modules/c++/sys/source/ConditionVarWin32.cpp new file mode 100644 index 000000000..893572825 --- /dev/null +++ b/modules/c++/sys/source/ConditionVarWin32.cpp @@ -0,0 +1,258 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#if defined(WIN32) && defined(_REENTRANT) + +#if !defined(USE_NSPR_THREADS) && !defined(__POSIX) + +#include "sys/ConditionVarWin32.h" + +namespace +{ + // RAII for EnterCriticalSection() / LeaveCriticalSection() + class ScopedCriticalSection + { + public: + ScopedCriticalSection(CRITICAL_SECTION& criticalSection) : + mCriticalSection(criticalSection) + { + EnterCriticalSection(&mCriticalSection); + } + + ~ScopedCriticalSection() + { + LeaveCriticalSection(&mCriticalSection); + } + + private: + CRITICAL_SECTION& mCriticalSection; + }; +} + +sys::ConditionVarDataWin32::ConditionVarDataWin32(): + mNumWaiters(0), + mSemaphore(CreateSemaphore(NULL, 0, 0x7FFFFFFF, NULL)), + mWaitersAreDone(CreateEvent(NULL, FALSE, FALSE, NULL)), + mWasBroadcast(false) +{ + InitializeCriticalSection(&mNumWaitersCS); + if (mSemaphore == NULL || mWaitersAreDone == NULL) + { + throw sys::SystemException( + "ConditionVarDataWin32 Initializer failed"); + } +} + +sys::ConditionVarDataWin32::~ConditionVarDataWin32() +{ + CloseHandle(mWaitersAreDone); + CloseHandle(mSemaphore); + DeleteCriticalSection(&mNumWaitersCS); +} + +void sys::ConditionVarDataWin32::wait(HANDLE externalMutex) +{ + // Increment # waiting + { + const ScopedCriticalSection lock(mNumWaitersCS); + ++mNumWaiters; + } + + // Atomically release the mutex and wait on the semaphore until signal() + // or broadcast() are called by another thread + if (SignalObjectAndWait(externalMutex, mSemaphore, INFINITE, FALSE) != + WAIT_OBJECT_0) + { + throw sys::SystemException("SignalObjectAndWait() failed"); + } + + waitImpl(externalMutex); +} + +bool sys::ConditionVarDataWin32::wait(HANDLE externalMutex, double timeout) +{ + if (timeout == 0) + { + wait(externalMutex); + return true; + } + + // Increment # waiting + { + const ScopedCriticalSection lock(mNumWaitersCS); + ++mNumWaiters; + } + + // Atomically release the mutex and wait on the semaphore until signal() + // or broadcast() are called by another thread or we time out + switch (SignalObjectAndWait(externalMutex, + mSemaphore, + static_cast(timeout * 1000), + FALSE)) + { + case WAIT_OBJECT_0: + waitImpl(externalMutex); + return true; + case WAIT_TIMEOUT: + return false; + default: + throw sys::SystemException("SignalObjectAndWait() failed"); + } +} + +void sys::ConditionVarDataWin32::waitImpl(HANDLE externalMutex) +{ + // Mark that we're no longer waiting + // If we woke up via broadcast(), determine if we're the last waiter + bool lastWaiter; + { + const ScopedCriticalSection lock(mNumWaitersCS); + --mNumWaiters; + lastWaiter = (mWasBroadcast && mNumWaiters == 0); + } + + if (lastWaiter) + { + // Atomically signals the mWaitersAreDone event and waits until it can + // acquire the external mutex. This is used to ensure fairness. + /// @note Fairness relies on the fact that Windows NT mutex requests + /// are queued in FIFO order. As a result, all waiting threads + /// will acquire the external mutex before any of them can + /// reacquire it a second time. + /// Need the atomicity of SignalObjectAndWait() here to ensure + /// that the last thread gets his chance to wait on the + /// external mutex. + SignalObjectAndWait(mWaitersAreDone, externalMutex, INFINITE, FALSE); + } + else + { + // We need to wait until we get the external mutex back + WaitForSingleObject(externalMutex, INFINITE); + } +} + +void sys::ConditionVarDataWin32::signal() +{ + bool haveWaiters; + { + const ScopedCriticalSection lock(mNumWaitersCS); + haveWaiters = mNumWaiters > 0; + } + + // If there are waiters, increment the semaphore by 1 to wake one up + if (haveWaiters) + { + ReleaseSemaphore(mSemaphore, 1, NULL); + } +} + +void sys::ConditionVarDataWin32::broadcast() +{ + bool haveWaiters; + { + const ScopedCriticalSection lock(mNumWaitersCS); + + // Increment the semaphore by the # of threads waiting + // This will allow all those threads to wake up in wait() + if (mNumWaiters > 0) + { + mWasBroadcast = true; + haveWaiters = true; + ReleaseSemaphore(mSemaphore, mNumWaiters, 0); + } + else + { + haveWaiters = false; + } + } + + if (haveWaiters) + { + // Wait for all the awakened threads to acquire mSemaphore + WaitForSingleObject(mWaitersAreDone, INFINITE); + + // This assignment is ok w/o locking the critical section + // since no waiter threads can wake up to access it + mWasBroadcast = false; + } +} + +sys::ConditionVarWin32::ConditionVarWin32() : + mMutexOwned(new sys::MutexWin32()), + mMutex(mMutexOwned.get()) +{} + +sys::ConditionVarWin32::ConditionVarWin32(sys::MutexWin32 *theLock, bool isOwner) : + mMutex(theLock) +{ + if (!theLock) + throw SystemException("ConditionVar received NULL mutex"); + + if (isOwner) + mMutexOwned.reset(theLock); +} + +void sys::ConditionVarWin32::acquireLock() +{ + mMutex->lock(); +} + +void sys::ConditionVarWin32::dropLock() +{ + mMutex->unlock(); +} + +void sys::ConditionVarWin32::wait(double timeout) +{ + dbg_printf("Timed waiting on condition [%f]\n", timeout); + if (!mNative.wait(mMutex->getNative(), timeout)) + throw sys::SystemException("Condition Variable wait failed"); +} + +void sys::ConditionVarWin32::wait() +{ + dbg_printf("Waiting on condition\n"); + mNative.wait(mMutex->getNative()); +} + +void sys::ConditionVarWin32::signal() +{ + dbg_printf("Signalling condition\n"); + mNative.signal(); +} + +void sys::ConditionVarWin32::broadcast() +{ + dbg_printf("Broadcasting condition\n"); + mNative.broadcast(); +} + +sys::ConditionVarDataWin32& sys::ConditionVarWin32::getNative() +{ + return mNative; +} + +#endif // No other thread package + +#endif // Windows + diff --git a/modules/c++/sys/source/Conf.cpp b/modules/c++/sys/source/Conf.cpp new file mode 100644 index 000000000..ccd1c9c64 --- /dev/null +++ b/modules/c++/sys/source/Conf.cpp @@ -0,0 +1,33 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#include "sys/Conf.h" + + +bool sys::isBigEndianSystem() +{ + // This is an endian test + int intVal = 1; + unsigned char* endianTest = (unsigned char*) & intVal; + return endianTest[0] != 1; +} diff --git a/modules/c++/sys/source/DLLUnix.cpp b/modules/c++/sys/source/DLLUnix.cpp new file mode 100644 index 000000000..b1a7da5cc --- /dev/null +++ b/modules/c++/sys/source/DLLUnix.cpp @@ -0,0 +1,86 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#if !defined(WIN32) + +#include "sys/DLL.h" + +void sys::DLLException::adjustMessage() +{ + if (!mMessage.empty() ) + { + mMessage += ": "; + } + mMessage += dlerror(); +} + +void sys::DLL::load(const std::string& libName) +{ + // First we get the library name in case you ask + mLibName = libName; + + // Next we load the library + mLib = dlopen( mLibName.c_str() , DLL_FLAGSET); + + // Now we check the return value + if (!mLib) + throw(sys::DLLException("Failed to load() DLL") ); + +} + +void sys::DLL::unload() +{ + // First we check to see if it's unloaded + if (mLib) + { + // Next we unload it or raise an exception + if (dlclose( mLib ) != 0) + throw(sys::DLLException("Failed to close library") ); + + // Now we reset member data + mLib = NULL; + mLibName.clear(); + } +} +DLL_FUNCTION_PTR +sys::DLL::retrieve(const std::string& functionName) +{ + // Check to make sure we have a library + if ( mLib != NULL ) + { + // Now we get a ptr + DLL_FUNCTION_PTR ptr = dlsym( mLib , functionName.c_str()); + + // Now we check the ptr value + if (ptr == NULL) + throw(sys::DLLException("Failed to load function")); + + return ptr; + } + else + { + throw(sys::DLLException("No library loaded") ); + }; +} + +#endif diff --git a/modules/c++/sys/source/DLLWin32.cpp b/modules/c++/sys/source/DLLWin32.cpp new file mode 100644 index 000000000..cfb7b9a36 --- /dev/null +++ b/modules/c++/sys/source/DLLWin32.cpp @@ -0,0 +1,89 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#if defined(WIN32) + +#include "sys/DLL.h" + +void sys::DLLException::adjustMessage() +{ + if (!mMessage.empty() ) + { + mMessage += ": "; + } + mMessage += sys::Err().toString(); +} + +void sys::DLL::load(const std::string& libName) +{ + // First we get the library name in case you ask + mLibName = libName; + + // Next we load the library + mLib = LoadLibrary( mLibName.c_str() ); + + + // Now we check the return value + if (!mLib) + throw(sys::DLLException(FmtX("Failed to load() DLL: %s", + mLibName.c_str() ) ) ); +} + +void sys::DLL::unload() +{ + // First we check to see if its unloaded + if (mLib) + { + // Next we unload it or raise an exception + FreeLibrary( mLib ); + + // Now we reset member data + mLib = NULL; + mLibName.clear(); + } +} + +DLL_FUNCTION_PTR sys::DLL:: +retrieve(const std::string& functionName) +{ + // Check to make sure we have a library + if ( mLib != NULL ) + { + // Now we get a ptr + DLL_FUNCTION_PTR ptr = (DLL_FUNCTION_PTR) + GetProcAddress(mLib, functionName.c_str()); + + // Now we check the ptr value + if (ptr == NULL) + throw(sys::DLLException(FmtX("Failed to load function: %s", + functionName.c_str()))); + return ptr; + } + else + { + throw(sys::DLLException("No library loaded") ); + }; +} + + +#endif diff --git a/modules/c++/sys/source/DateTime.cpp b/modules/c++/sys/source/DateTime.cpp new file mode 100644 index 000000000..c60030524 --- /dev/null +++ b/modules/c++/sys/source/DateTime.cpp @@ -0,0 +1,275 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include "except/Exception.h" +#include "sys/DateTime.h" +#include "str/Convert.h" +#include "str/Manip.h" +#include + +#if defined(HAVE_SYS_TIME_H) +#include +#elif defined(_WIN32) +#include +#endif + +void sys::DateTime::fromMillis() +{ + tm t; + getTime(t); + fromMillis(t); +} + +void sys::DateTime::fromMillis(const tm& t) +{ + // this is year since 1900 so need to add that + mYear = t.tm_year + 1900; + // 0-based so add 1 + mMonth = t.tm_mon + 1; + mDayOfMonth = t.tm_mday; + mDayOfWeek = t.tm_wday + 1; + mDayOfYear = t.tm_yday + 1; + mHour = t.tm_hour; + mMinute = t.tm_min; + + const size_t timeInSeconds = (size_t)(mTimeInMillis / 1000); + const double timediff = ((double)mTimeInMillis / 1000.0) - timeInSeconds; + mSecond = t.tm_sec + timediff; +} + +double sys::DateTime::toMillis(tm t) const +{ + time_t timeInSeconds = mktime(&t); + double timediff = mSecond - t.tm_sec; + return (timeInSeconds + timediff) * 1000; +} + +void sys::DateTime::setNow() +{ +#if defined(__POSIX) && defined(USE_CLOCK_GETTIME) + struct timespec now; + clock_gettime(CLOCK_REALTIME,&now); + mTimeInMillis = (now.tv_sec + 1.0e-9 * now.tv_nsec) * 1000; +#elif defined(HAVE_SYS_TIME_H) + struct timeval now; + gettimeofday(&now,NULL); + mTimeInMillis = (now.tv_sec + 1.0e-6 * now.tv_usec) * 1000; +#elif defined(_WIN32) + // Getting time twice may be inefficient but is quicker + // than converting the SYSTEMTIME structure into + // milliseconds + // We could add an additional flag here if the user + // does not need millisecond accuracy + SYSTEMTIME now; + GetLocalTime(&now); + mTimeInMillis = (double)time(NULL) * 1000 + now.wMilliseconds; +#else + mTimeInMillis = (double)time(NULL) * 1000; +#endif + fromMillis(); +} + +void sys::DateTime::getTime(tm& t) const +{ + getTime(static_cast(mTimeInMillis / 1000), t); +} + +sys::DateTime::DateTime() : + mYear(0), + mMonth(0), + mDayOfMonth(0), + mDayOfWeek(0), + mDayOfYear(0), + mHour(0), + mMinute(0), + mSecond(0.0), + mTimeInMillis(0.0) +{ } + +sys::DateTime::~DateTime() +{} + +std::string sys::DateTime::monthToString(int month) +{ + switch (month) + { + case 1: { return "January"; }break; + case 2: { return "February"; }break; + case 3: { return "March"; }break; + case 4: { return "April"; }break; + case 5: { return "May"; }break; + case 6: { return "June"; }break; + case 7: { return "July"; }break; + case 8: { return "August"; }break; + case 9: { return "September"; }break; + case 10: { return "October"; }break; + case 11: { return "November"; }break; + case 12: { return "December"; }break; + default: throw new except::InvalidArgumentException( + "Value not in the valid range {1:12}"); + } +} + +std::string sys::DateTime::dayOfWeekToString(int dayOfWeek) +{ + switch (dayOfWeek) + { + case 1: { return "Sunday"; }break; + case 2: { return "Monday"; }break; + case 3: { return "Tuesday"; }break; + case 4: { return "Wednesday"; }break; + case 5: { return "Thursday"; }break; + case 6: { return "Friday"; }break; + case 7: { return "Saturday"; }break; + default: throw new except::InvalidArgumentException( + "Value not in the valid range {1:7}"); + } +} + +std::string sys::DateTime::monthToStringAbbr(int month) +{ + return monthToString(month).substr(0,3); +} + +std::string sys::DateTime::dayOfWeekToStringAbbr(int dayOfWeek) +{ + return dayOfWeekToString(dayOfWeek).substr(0,3); +} + +int monthToValue(const std::string& month) +{ + std::string m = month; + str::lower(m); + + if (str::startsWith(m, "jan")) + return 1; + else if (str::startsWith(m, "feb")) + return 2; + else if (str::startsWith(m, "mar")) + return 3; + else if (str::startsWith(m, "apr")) + return 4; + else if (str::startsWith(m, "may")) + return 5; + else if (str::startsWith(m, "jun")) + return 6; + else if (str::startsWith(m, "jul")) + return 7; + else if (str::startsWith(m, "aug")) + return 8; + else if (str::startsWith(m, "sep")) + return 9; + else if (str::startsWith(m, "oct")) + return 10; + else if (str::startsWith(m, "nov")) + return 11; + else if (str::startsWith(m, "dec")) + return 12; + else + throw new except::InvalidArgumentException( + "Value not in the valid range {Jan:Dec}"); +} + +int dayOfWeekToValue(const std::string& dayOfWeek) +{ + std::string d = dayOfWeek; + str::lower(d); + + if (str::startsWith(d, "sun")) + return 1; + else if (str::startsWith(d, "mon")) + return 2; + else if (str::startsWith(d, "tue")) + return 3; + else if (str::startsWith(d, "wed")) + return 4; + else if (str::startsWith(d, "thu")) + return 5; + else if (str::startsWith(d, "fri")) + return 6; + else if (str::startsWith(d, "sat")) + return 7; + else + throw new except::InvalidArgumentException( + "Value not in the valid range {Sun:Sat}"); +} + +void sys::DateTime::setDayOfMonth(int dayOfMonth) +{ + mDayOfMonth = dayOfMonth; + toMillis(); +} + +void sys::DateTime::setMonth(int month) +{ + mMonth = month; + toMillis(); +} + +void sys::DateTime::setHour(int hour) +{ + mHour = hour; + toMillis(); +} + +void sys::DateTime::setMinute(int minute) +{ + mMinute = minute; + toMillis(); +} + +void sys::DateTime::setSecond(double second) +{ + mSecond = second; + toMillis(); +} + +void sys::DateTime::setTimeInMillis(double time) +{ + mTimeInMillis = time; + fromMillis(); +} + +void sys::DateTime::setYear(int year) +{ + mYear = year; + toMillis(); +} + +std::string sys::DateTime::format(const std::string& formatStr) const +{ + // the longest string expansion is + // %c => 'Thu Aug 23 14:55:02 2001' + // which is an expansion of 22 characters + size_t maxSize = formatStr.length() * 22 + 1; + std::vector expanded(maxSize); + char* str = &expanded[0]; + + tm localTime; + getTime(localTime); + if (!strftime(str, maxSize, formatStr.c_str(), &localTime)) + throw except::InvalidFormatException( + "The format string was unable to be expanded"); + + return std::string(str); +} + diff --git a/modules/c++/sys/source/Dbg.cpp b/modules/c++/sys/source/Dbg.cpp new file mode 100644 index 000000000..c27f3ed46 --- /dev/null +++ b/modules/c++/sys/source/Dbg.cpp @@ -0,0 +1,45 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#include "sys/Dbg.h" + +void sys::dbgPrintf(const char *format, ...) +{ +#ifdef __DEBUG + va_list args; + va_start(args, format); + fprintf(DEBUG_STREAM, " "); + vfprintf(DEBUG_STREAM, format, args); + va_end(args); +#endif +} + +void sys::diePrintf(const char *format, ...) +{ + va_list args; + va_start(args, format); + vfprintf(DEBUG_STREAM, format, args); + va_end(args); + exit(EXIT_FAILURE); +} + diff --git a/modules/c++/sys/source/DirectoryEntry.cpp b/modules/c++/sys/source/DirectoryEntry.cpp new file mode 100644 index 000000000..7a2e9388d --- /dev/null +++ b/modules/c++/sys/source/DirectoryEntry.cpp @@ -0,0 +1,56 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#include "sys/DirectoryEntry.h" + +bool operator==(const sys::DirectoryEntry::Iterator& lhs, + const sys::DirectoryEntry::Iterator& rhs) +{ + const sys::DirectoryEntry* lhsD = lhs.get(); + const sys::DirectoryEntry* rhsD = rhs.get(); + if (!lhsD || !rhsD) + { + if (lhsD == rhsD) return true; + return false; + } + else + return ( (lhsD->getName() == rhsD->getName() ) && + (lhsD->getCurrent() == rhsD->getCurrent()) + ); + +} +bool operator!=(const sys::DirectoryEntry::Iterator& lhs, + const sys::DirectoryEntry::Iterator& rhs) +{ + const sys::DirectoryEntry* lhsD = lhs.get(); + const sys::DirectoryEntry* rhsD = rhs.get(); + if (!lhsD || !rhsD) + { + if (lhsD != rhsD) return true; + return false; + } + else + return ( (lhsD->getName() != rhsD->getName() ) || + (lhsD->getCurrent() != rhsD->getCurrent()) + ); +} diff --git a/modules/c++/sys/source/ErrUnix.cpp b/modules/c++/sys/source/ErrUnix.cpp new file mode 100644 index 000000000..844353fe0 --- /dev/null +++ b/modules/c++/sys/source/ErrUnix.cpp @@ -0,0 +1,49 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#if !defined(WIN32) + +#include "sys/Err.h" + +int sys::Err::getLast() const +{ + return errno; +} + +std::string sys::Err::toString() const +{ + char *temp = strerror(mErrId); + if (temp == NULL) + return std::string(""); + + std::string stringError = temp; + return stringError; +} + +int sys::SocketErr::getLast() const +{ + return errno; +} + +#endif + diff --git a/modules/c++/sys/source/ErrWin32.cpp b/modules/c++/sys/source/ErrWin32.cpp new file mode 100644 index 000000000..f3ebf414c --- /dev/null +++ b/modules/c++/sys/source/ErrWin32.cpp @@ -0,0 +1,55 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#if defined(WIN32) + +#include +#include "sys/Err.h" + +int sys::Err::getLast() const +{ + return GetLastError(); +} + +std::string sys::Err::toString() const +{ + LPTSTR buffer; + if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM, NULL, + mErrId, 0, + (LPTSTR)&buffer, 0, NULL) == 0) + { + return std::string("Unknown error code"); + } + + std::string error(buffer); + LocalFree(buffer); + return error; +} + +int sys::SocketErr::getLast() const +{ + return WSAGetLastError(); +} + +#endif diff --git a/modules/c++/sys/source/ExecUnix.cpp b/modules/c++/sys/source/ExecUnix.cpp new file mode 100644 index 000000000..5f6fa25e0 --- /dev/null +++ b/modules/c++/sys/source/ExecUnix.cpp @@ -0,0 +1,81 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#if !defined(WIN32) + +#include +#include "sys/Exec.h" + +int sys::ExecPipe::closePipe() +{ + if (!mOutStream) + { + throw except::IOException( + Ctxt("The stream is already closed")); + } + + // in case it fails + FILE* tmp = mOutStream; + mOutStream = NULL; + + int exitStatus = 0; + const int encodedStatus = pclose(tmp); + + if (WIFEXITED(encodedStatus)) + { + // get exit code from child process + exitStatus = WEXITSTATUS(encodedStatus); + + } + else + { + //! unix gives a little better granularity on errors + + // due to uncaught signal (ex. segFault) + if (WIFSIGNALED(encodedStatus)) + { + throw except::IOException( + Ctxt("The child process was terminated by " \ + "an uncaught signal: " + + str::toString(WTERMSIG(encodedStatus)))); + } + // due to unplanned stoppage + if (WIFSTOPPED(encodedStatus)) + { + throw except::IOException( + Ctxt("The child process was unexpectedly stopped: " + + str::toString(WSTOPSIG(encodedStatus)))); + } + + // all other errors + sys::SocketErr err; + throw except::IOException( + Ctxt("Failure while closing stream to child process: " + + err.toString())); + } + + return exitStatus; +} + +#endif + diff --git a/modules/c++/sys/source/ExecWin32.cpp b/modules/c++/sys/source/ExecWin32.cpp new file mode 100644 index 000000000..d8904f92a --- /dev/null +++ b/modules/c++/sys/source/ExecWin32.cpp @@ -0,0 +1,54 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#if defined(WIN32) + +#include "sys/Err.h" +#include "sys/Exec.h" + +int sys::ExecPipe::closePipe() +{ + if (!mOutStream) + { + throw except::IOException( + Ctxt("The stream is already closed")); + } + + // in case it fails + FILE* tmp = mOutStream; + mOutStream = NULL; + + const int exitStatus = pclose(tmp); + if (exitStatus == -1) + { + sys::SocketErr err; + throw except::IOException( + Ctxt("Failure while closing stream to child process: " + + err.toString())); + + } + + return exitStatus; +} + +#endif diff --git a/modules/c++/sys/source/FileFinder.cpp b/modules/c++/sys/source/FileFinder.cpp new file mode 100644 index 000000000..9d137402c --- /dev/null +++ b/modules/c++/sys/source/FileFinder.cpp @@ -0,0 +1,204 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include +#include "sys/FileFinder.h" +#include "sys/DirectoryEntry.h" +#include "sys/Path.h" + +bool sys::ExistsPredicate::operator()(const std::string& entry) const +{ + return sys::Path(entry).exists(); +} + +bool sys::FileOnlyPredicate::operator()(const std::string& entry) const +{ + return sys::Path(entry).isFile(); +} + +bool sys::DirectoryOnlyPredicate::operator()(const std::string& entry) const +{ + return sys::Path(entry).isDirectory(); +} + +sys::FragmentPredicate::FragmentPredicate(const std::string& fragment, + bool ignoreCase) : + mFragment(fragment), mIgnoreCase(ignoreCase) +{ +} + +bool sys::FragmentPredicate::operator()(const std::string& entry) const +{ + if (mIgnoreCase) + { + std::string base = entry; + str::lower(base); + + std::string match = mFragment; + str::lower(match); + + return str::contains(base, match); + } + else + return str::contains(entry, mFragment); +} + + +sys::ExtensionPredicate::ExtensionPredicate(const std::string& ext, + bool ignoreCase) : + mExt(ext), mIgnoreCase(ignoreCase) +{ +} + +bool sys::ExtensionPredicate::operator()(const std::string& filename) const +{ + if (!sys::FileOnlyPredicate::operator()(filename)) + return false; + + std::string ext = sys::Path::splitExt(filename).second; + if (mIgnoreCase) + { + std::string matchExt = mExt; + str::lower(matchExt); + str::lower(ext); + return ext == matchExt; + } + else + return ext == mExt; +} + +sys::NotPredicate::NotPredicate(FilePredicate* filter, bool ownIt) : + mPredicate(sys::NotPredicate::PredicatePair(filter, ownIt)) +{ +} + +sys::NotPredicate::~NotPredicate() +{ + if (mPredicate.second && mPredicate.first) + { + FilePredicate* tmp = mPredicate.first; + mPredicate.first = NULL; + delete tmp; + } +} + +bool sys::NotPredicate::operator()(const std::string& entry) const +{ + return !(*mPredicate.first)(entry); +} + +sys::LogicalPredicate::LogicalPredicate(bool orOperator) : + mOrOperator(orOperator) +{ +} + +sys::LogicalPredicate::~LogicalPredicate() +{ + for (size_t i = 0; i < mPredicates.size(); ++i) + { + sys::LogicalPredicate::PredicatePair& p = mPredicates[i]; + if (p.first && p.second) + { + sys::FilePredicate* tmp = p.first; + p.first = NULL; + delete tmp; + } + } +} + +bool sys::LogicalPredicate::operator()(const std::string& entry) const +{ + bool ok = !mOrOperator; + for (size_t i = 0, n = mPredicates.size(); i < n && ok != mOrOperator; ++i) + { + const sys::LogicalPredicate::PredicatePair& p = mPredicates[i]; + if (mOrOperator) + ok |= (p.first && (*p.first)(entry)); + else + ok &= (p.first && (*p.first)(entry)); + } + return ok; +} + +sys::LogicalPredicate& sys::LogicalPredicate::addPredicate( + FilePredicate* filter, + bool ownIt) +{ + mPredicates.push_back( + sys::LogicalPredicate::PredicatePair( + filter, ownIt)); + return *this; +} + +std::vector sys::FileFinder::search( + const FilePredicate& filter, + const std::vector& searchPaths, + bool recursive) +{ + // turn it into a list so we can queue additional entries + std::list < std::string > paths; + std::copy(searchPaths.begin(), searchPaths.end(), + std::back_inserter(paths)); + + std::vector files; + size_t numInputPaths = searchPaths.size(); + for (size_t pathIdx = 0; !paths.empty(); ++pathIdx) + { + sys::Path path(paths.front()); + paths.pop_front(); + + //! check if it exists + if (path.exists()) + { + // check if this meets the criteria -- + // we only need one to add it + if (filter(path.getPath())) + { + files.push_back(path.getPath()); + } + + // if it's a directory we need to search its contents + if (path.isDirectory()) + { + // If its an original directory or we are recursively searching + if (pathIdx < numInputPaths || recursive) + { + sys::DirectoryEntry d(path.getPath()); + for (sys::DirectoryEntry::Iterator p = d.begin(); + p != d.end(); ++p) + { + std::string fname(*p); + if (fname != "." && fname != "..") + { + // add it to the list + paths.push_back(sys::Path::joinPaths(path.getPath(), + fname)); + } + } + } + } + + } + } + return files; +} + diff --git a/modules/c++/sys/source/FileUnix.cpp b/modules/c++/sys/source/FileUnix.cpp new file mode 100644 index 000000000..82836eb48 --- /dev/null +++ b/modules/c++/sys/source/FileUnix.cpp @@ -0,0 +1,157 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include "sys/File.h" + +#ifndef WIN32 + +#include +#include +#include + +void sys::File::create(const std::string& str, int accessFlags, + int creationFlags) throw (sys::SystemException) +{ + + if (accessFlags & sys::File::WRITE_ONLY) + creationFlags |= sys::File::TRUNCATE; + mHandle = open(str.c_str(), accessFlags | creationFlags, _SYS_DEFAULT_PERM); + + if (mHandle < 0) + { + throw sys::SystemException(Ctxt(FmtX("Error opening file [%d]: [%s]", + mHandle, str.c_str()))); + } + mPath = str; +} + +void sys::File::readInto(char *buffer, Size_T size) + throw (sys::SystemException) +{ + SSize_T bytesRead = 0; + Size_T totalBytesRead = 0; + int i; + + /* make sure the user actually wants data */ + if (size == 0) + return; + + for (i = 1; i <= _SYS_MAX_READ_ATTEMPTS; i++) + { + bytesRead = ::read(mHandle, buffer + totalBytesRead, size + - totalBytesRead); + + switch (bytesRead) + { + case -1: /* Some type of error occured */ + switch (errno) + { + case EINTR: + case EAGAIN: /* A non-fatal error occured, keep trying */ + break; + + default: /* We failed */ + throw sys::SystemException("While reading from file"); + } + break; + + case 0: /* EOF (unexpected) */ + throw sys::SystemException(Ctxt("Unexpected end of file")); + + default: /* We made progress */ + totalBytesRead += bytesRead; + + } /* End of switch */ + + /* Check for success */ + if (totalBytesRead == size) + { + return; + } + } + throw sys::SystemException(Ctxt("Unknown read state")); +} + +void sys::File::writeFrom(const char *buffer, Size_T size) + throw (sys::SystemException) +{ + Size_T bytesActuallyWritten = 0; + + do + { + const SSize_T bytesThisRead = ::write(mHandle, + buffer + bytesActuallyWritten, + size - bytesActuallyWritten); + if (bytesThisRead == -1) + { + throw sys::SystemException(Ctxt("Writing to file")); + } + bytesActuallyWritten += bytesThisRead; + } + while (bytesActuallyWritten < size); +} + +sys::Off_T sys::File::seekTo(sys::Off_T offset, int whence) + throw (sys::SystemException) +{ + sys::Off_T off = ::lseek(mHandle, offset, whence); + if (off == (sys::Off_T) - 1) + throw sys::SystemException(Ctxt("Seeking in file")); + return off; +} + +sys::Off_T sys::File::length() throw (sys::SystemException) +{ + struct stat buf; + int rval = fstat(mHandle, &buf); + if (rval == -1) + throw sys::SystemException(Ctxt("Error querying file attributes")); + return buf.st_size; +} + +sys::Off_T sys::File::lastModifiedTime() throw (sys::SystemException) +{ + struct stat buf; + int rval = fstat(mHandle, &buf); + if (rval == -1) + throw sys::SystemException(Ctxt("Error querying file attributes")); + return (sys::Off_T) buf.st_mtime * 1000; +} + +void sys::File::flush() +{ + if (::fsync(mHandle) != 0) + { + const int errnum = errno; + throw sys::SystemException(Ctxt( + "Error flushing file " + mPath + " (" + ::strerror(errnum) + ")")); + } +} + +void sys::File::close() +{ + ::close(mHandle); + mHandle = SYS_INVALID_HANDLE; +} + +#endif + diff --git a/modules/c++/sys/source/FileWin32.cpp b/modules/c++/sys/source/FileWin32.cpp new file mode 100644 index 000000000..428166ec6 --- /dev/null +++ b/modules/c++/sys/source/FileWin32.cpp @@ -0,0 +1,173 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifdef WIN32 + +#include +#include +#include "sys/File.h" + +void sys::File::create(const std::string& str, + int accessFlags, + int creationFlags) +{ + // If the truncate bit is on AND the file does exist, + // we need to set the mode to TRUNCATE_EXISTING + if ((creationFlags & sys::File::TRUNCATE) && sys::OS().exists(str) ) + { + creationFlags = TRUNCATE_EXISTING; + } + else + { + creationFlags = ~sys::File::TRUNCATE & creationFlags; + } + + mHandle = CreateFile(str.c_str(), + accessFlags, + FILE_SHARE_READ, NULL, + creationFlags, + FILE_ATTRIBUTE_NORMAL, NULL); + + if (mHandle == SYS_INVALID_HANDLE) + { + throw sys::SystemException(Ctxt(FmtX("Error opening file: [%s]", str.c_str()))); + } + mPath = str; +} + +void sys::File::readInto(char *buffer, Size_T size) +{ + static const DWORD MAX_READ_SIZE = std::numeric_limits::max(); + size_t bytesRead = 0; + size_t bytesRemaining = size; + + while (bytesRead < size) + { + // Determine how many bytes to read + const DWORD bytesToRead = + std::min(MAX_READ_SIZE, bytesRemaining); + + // Read from file + DWORD bytesThisRead = 0; + if (!ReadFile(mHandle, + buffer + bytesRead, + bytesToRead, + &bytesThisRead, + NULL)) + { + throw sys::SystemException(Ctxt("Error reading from file")); + } + else if (bytesThisRead == 0) + { + //! ReadFile does not fail when finding the EOF -- + // instead it reports 0 bytes read, so this stops an infinite loop + // from Unexpected EOF + throw sys::SystemException(Ctxt("Unexpected end of file")); + } + + bytesRead += bytesThisRead; + bytesRemaining -= bytesThisRead; + } +} + +void sys::File::writeFrom(const char *buffer, Size_T size) +{ + static const DWORD MAX_WRITE_SIZE = std::numeric_limits::max(); + size_t bytesRemaining = size; + size_t bytesWritten = 0; + + while (bytesWritten < size) + { + // Determine how many bytes to write + const DWORD bytesToWrite = + std::min(MAX_WRITE_SIZE, bytesRemaining); + + // Write the data + DWORD bytesThisWrite = 0; + if (!WriteFile(mHandle, + buffer + bytesWritten, + bytesToWrite, + &bytesThisWrite, + NULL)) + { + throw sys::SystemException(Ctxt("Writing from file")); + } + + // Accumulate this write until we are done + bytesRemaining -= bytesThisWrite; + bytesWritten += bytesThisWrite; + } +} + +sys::Off_T sys::File::seekTo(sys::Off_T offset, int whence) +{ + /* Ahhh!!! */ + LARGE_INTEGER largeInt; + LARGE_INTEGER toWhere; + largeInt.QuadPart = offset; + if (!SetFilePointerEx(mHandle, largeInt, &toWhere, whence)) + throw sys::SystemException(Ctxt("SetFilePointer failed")); + + return (sys::Off_T) toWhere.QuadPart; +} + +sys::Off_T sys::File::length() +{ + DWORD highOff; + DWORD ret = GetFileSize(mHandle, &highOff); + sys::Uint64_T off = highOff; + return (sys::Off_T)(off << 32) + ret; +} + +sys::Off_T sys::File::lastModifiedTime() +{ + FILETIME creationTime, lastAccessTime, lastWriteTime; + BOOL ret = GetFileTime(mHandle, &creationTime, + &lastAccessTime, &lastWriteTime); + if (ret) + { + ULARGE_INTEGER uli; + uli.LowPart = lastWriteTime.dwLowDateTime; + uli.HighPart = lastWriteTime.dwHighDateTime; + ULONGLONG stInMillis(uli.QuadPart/10000); + return (sys::Off_T)stInMillis; + } + throw sys::SystemException(Ctxt( + FmtX("Error getting last modified time for path %s", + mPath.c_str()))); +} + +void sys::File::flush() +{ + if (!FlushFileBuffers(mHandle)) + { + throw sys::SystemException(Ctxt("Error flushing file " + mPath)); + } +} + +void sys::File::close() +{ + CloseHandle(mHandle); + mHandle = SYS_INVALID_HANDLE; +} + +#endif diff --git a/modules/c++/sys/source/LocalDateTime.cpp b/modules/c++/sys/source/LocalDateTime.cpp new file mode 100755 index 000000000..fd8411d3a --- /dev/null +++ b/modules/c++/sys/source/LocalDateTime.cpp @@ -0,0 +1,145 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include "sys/LocalDateTime.h" + +#include "sys/Conf.h" +#include "except/Exception.h" +#include "str/Convert.h" +#include "str/Manip.h" + +#include + +const char sys::LocalDateTime::DEFAULT_DATETIME_FORMAT[] = "%Y-%m-%d_%H:%M:%S"; + + +void sys::LocalDateTime::fromMillis(const tm& t) +{ + DateTime::fromMillis(t); + mDST = t.tm_isdst; +} + +void sys::LocalDateTime::toMillis() +{ + tm t; + t.tm_year = mYear - 1900; + t.tm_mon = mMonth - 1; + t.tm_mday = mDayOfMonth; + t.tm_wday = mDayOfWeek + 1; + t.tm_yday = mDayOfYear - 1; + t.tm_hour = mHour; + t.tm_min = mMinute; + t.tm_sec = (int)mSecond; + t.tm_isdst = mDST; + + mTimeInMillis = DateTime::toMillis(t); +} + +void sys::LocalDateTime::getTime(time_t numSecondsSinceEpoch, tm& t) const +{ + // Would like to use the reentrant version. If we don't have one, cross + // our fingers and hope the regular function actually is reentrant + // (supposedly this is the case on Windows). +#ifdef HAVE_LOCALTIME_R + if (::localtime_r(&numSecondsSinceEpoch, &t) == NULL) + { + int const errnum = errno; + throw except::Exception(Ctxt("localtime_r() failed (" + + std::string(::strerror(errnum)) + ")")); + } +#else + tm const * const localTimePtr = ::localtime(&numSecondsSinceEpoch); + if (localTimePtr == NULL) + { + int const errnum = errno; + throw except::Exception(Ctxt("localtime failed (" + + std::string(::strerror(errnum)) + ")")); + } + t = *localTimePtr; +#endif +} + +sys::LocalDateTime::LocalDateTime() : + mDST(-1) // Tell mktime() we're not sure +{ + setNow(); + toMillis(); +} + +sys::LocalDateTime::LocalDateTime(int hour, int minute, double second) : + mDST(-1) // Tell mktime() we're not sure +{ + setNow(); + + mHour = hour; + mMinute = minute; + mSecond = second; + + toMillis(); +} + +sys::LocalDateTime::LocalDateTime(int year, int month, int day) : + mDST(-1) // Tell mktime() we're not sure +{ + mYear = year; + mMonth = month; + mDayOfMonth = day; + + toMillis(); + DateTime::fromMillis(); +} + +sys::LocalDateTime::LocalDateTime(int year, int month, int day, + int hour, int minute, double second) : + mDST(-1) // Tell mktime() we're not sure +{ + mYear = year; + mMonth = month; + mDayOfMonth = day; + mHour = hour; + mMinute = minute; + mSecond = second; + + toMillis(); + DateTime::fromMillis(); +} + +sys::LocalDateTime::LocalDateTime(double timeInMillis) : + mDST(-1) // Tell mktime() we're not sure +{ + mTimeInMillis = timeInMillis; + DateTime::fromMillis(); +} + +void sys::LocalDateTime::setDST(bool isDST) +{ + if(isDST) + mDST = 1; + else + mDST = 0; +} + +std::string sys::LocalDateTime::format() const +{ + return format(DEFAULT_DATETIME_FORMAT); +} + diff --git a/modules/c++/sys/source/MutexIrix.cpp b/modules/c++/sys/source/MutexIrix.cpp new file mode 100644 index 000000000..df5cdde75 --- /dev/null +++ b/modules/c++/sys/source/MutexIrix.cpp @@ -0,0 +1,61 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#if defined(__sgi) && defined(_REENTRANT) && !defined(__POSIX) +#include +#include "sys/MutexIrix.h" +#include "sys/SyncFactoryIrix.h" + +sys::MutexIrix::MutexIrix() +{ + if (!sys::SyncFactoryIrix().createLock(*this)) + throw SystemException("Mutex initialization failed"); +} + +sys::MutexIrix::~MutexIrix() +{ + dbg_printf("~MutexIrix()\n"); + sys::SyncFactoryIrix().destroyLock(*this); +} + +void sys::MutexIrix::lock() +{ + dbg_printf("MutexIrix::lock()\n"); + if (!sys::SyncFactoryIrix().setLock(*this)) + throw sys::SystemException("Mutex lock failed"); +} + +void sys::MutexIrix::unlock() +{ + dbg_printf("MutexIrix::unlock()\n"); + if (!sys::SyncFactoryIrix().unsetLock(*this)) + throw sys::SystemException("Mutex unlock failed"); +} + +ulock_t*& sys::MutexIrix::getNative() +{ + return mNative; +} + +#endif // __sgi && _REENTRANT && !__POSIX + diff --git a/modules/c++/sys/source/MutexNSPR.cpp b/modules/c++/sys/source/MutexNSPR.cpp new file mode 100644 index 000000000..c3ef4b6bf --- /dev/null +++ b/modules/c++/sys/source/MutexNSPR.cpp @@ -0,0 +1,56 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#if defined(USE_NSPR_THREADS) && defined(_REENTRANT) +#include "sys/MutexNSPR.h" + +sys::MutexNSPR::MutexNSPR() +{ + mNative = PR_NewLock(); + if (mNative == NULL) + throw sys::SystemException("Mutex initialization failed"); +} +sys::MutexNSPR::~MutexNSPR() +{ + if (mNative != NULL) + PR_DestroyLock(mNative); +} +void sys::MutexNSPR::lock() +{ + PR_Lock(mNative); +} + +void sys::MutexNSPR::unlock() +{ + PRStatus status = PR_Unlock(mNative); + if (status == PR_FAILURE) + throw sys::SystemException("Mutex unlock failed"); +} + +PRLock*& sys::MutexNSPR::getNative() +{ + return mNative; +} + +#endif + diff --git a/modules/c++/sys/source/MutexPosix.cpp b/modules/c++/sys/source/MutexPosix.cpp new file mode 100644 index 000000000..7c07d15b5 --- /dev/null +++ b/modules/c++/sys/source/MutexPosix.cpp @@ -0,0 +1,67 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#if defined(__POSIX) && defined(_REENTRANT) +#include "sys/MutexPosix.h" + +sys::MutexPosix::MutexPosix() +{ + if (::pthread_mutex_init(&mNative, NULL) != 0) + throw sys::SystemException("Mutex initialization failed"); +} + +sys::MutexPosix::~MutexPosix() +{ + if ( ::pthread_mutex_destroy(&mNative) == -1 ) + { + ::pthread_mutex_unlock(&mNative); + ::pthread_mutex_destroy(&mNative); + } +} + +void sys::MutexPosix::lock() +{ +#ifdef THREAD_DEBUG + dbg_printf("Locking mutex\n"); +#endif + if (::pthread_mutex_lock(&mNative) != 0) + throw new sys::SystemException("Mutex lock failed"); +} + +void sys::MutexPosix::unlock() +{ +#ifdef THREAD_DEBUG + dbg_printf("Unlocking mutex\n"); +#endif + if (::pthread_mutex_unlock(&mNative) != 0) + throw sys::SystemException("Mutex unlock failed"); + +} + +pthread_mutex_t& sys::MutexPosix::getNative() +{ + return mNative; +} + +#endif // __POSIX && _REENTRANT + diff --git a/modules/c++/sys/source/MutexSolaris.cpp b/modules/c++/sys/source/MutexSolaris.cpp new file mode 100644 index 000000000..6193eeda5 --- /dev/null +++ b/modules/c++/sys/source/MutexSolaris.cpp @@ -0,0 +1,66 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#if defined(__sun) && defined(_REENTRANT) && !defined(__POSIX) +#include "sys/MutexSolaris.h" + +sys::MutexSolaris::MutexSolaris() +{ + if (::mutex_init(&mNative, USYNC_THREAD, NULL) != 0) + throw sys::SystemException("Mutex initialization failed"); +} + +sys::MutexSolaris::~MutexSolaris() +{ + if ( ::mutex_destroy(&mNative) != 0 ) + { + ::mutex_unlock(&mNative); + ::mutex_destroy(&mNative); + } +} + +void sys::MutexSolaris::lock() +{ +#ifdef THREAD_DEBUG + dbg_printf("Locking mutex\n"); +#endif + if (::mutex_lock(&mNative) != 0) + throw sys::SystemException("Mutex lock failed"); +} + +void sys::MutexSolaris::unlock() +{ +#ifdef THREAD_DEBUG + dbg_printf("Unlocking mutex\n"); +#endif + if (::mutex_unlock(&mNative) != 0) + throw sys::SystemException("Mutex unlock failed"); +} + +mutex_t& sys::MutexSolaris::getNative() +{ + return mNative; +} + +#endif + diff --git a/modules/c++/sys/source/MutexWin32.cpp b/modules/c++/sys/source/MutexWin32.cpp new file mode 100644 index 000000000..8080a67f4 --- /dev/null +++ b/modules/c++/sys/source/MutexWin32.cpp @@ -0,0 +1,61 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#if defined(WIN32) && defined(_REENTRANT) + +#if !defined(USE_NSPR_THREADS) && !defined(__POSIX) + +#include "sys/MutexWin32.h" + +sys::MutexWin32::MutexWin32() +{ + mNative = CreateMutex(NULL, FALSE, NULL); + if (mNative == NULL) + throw sys::SystemException("Mutex initializer failed"); +} + +sys::MutexWin32::~MutexWin32() +{ + CloseHandle(mNative); +} + +void sys::MutexWin32::lock() +{ + if (WaitForSingleObject(mNative, INFINITE) == WAIT_FAILED) + throw sys::SystemException("Mutex lock failed"); +} + +void sys::MutexWin32::unlock() +{ + if (ReleaseMutex(mNative) != TRUE) + throw sys::SystemException("Mutex unlock failed"); +} + +HANDLE& sys::MutexWin32::getNative() +{ + return mNative; +} + +#endif // Not some other thread package + +#endif // Windows platform diff --git a/modules/c++/sys/source/OSUnix.cpp b/modules/c++/sys/source/OSUnix.cpp new file mode 100644 index 000000000..f632368c3 --- /dev/null +++ b/modules/c++/sys/source/OSUnix.cpp @@ -0,0 +1,249 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#if !defined(WIN32) + +#include +#include +#include + +#include "sys/OSUnix.h" +#include "sys/File.h" + +std::string sys::OSUnix::getPlatformName() const +{ + struct utsname name; + if (uname(&name) == -1) + throw sys::SystemException("Uname failed"); + + return FmtX("%s (%s): %s [build: %s]", name.sysname, name.machine, + name.release, name.version); +} + +std::string sys::OSUnix::getNodeName() const +{ + struct utsname name; + if (uname(&name) == -1) + throw sys::SystemException("Uname failed"); + + return std::string(name.nodename); +} + + +bool sys::OSUnix::exists(const std::string& path) const +{ + struct stat info; + if (stat(path.c_str(), &info) == -1) + return false; + return true; +} + +bool sys::OSUnix::removeFile(const std::string& pathname) const +{ + return (::unlink(pathname.c_str()) == 0); +} + +bool sys::OSUnix::removeDirectory(const std::string& pathname) const +{ + return (::rmdir(pathname.c_str()) == 0); +} + +bool sys::OSUnix::move(const std::string& path, + const std::string& newPath) const +{ + return (::rename(path.c_str(), newPath.c_str()) == 0); +} + +sys::Pid_T sys::OSUnix::getProcessId() const +{ + return ::getpid(); +} + +bool sys::OSUnix::makeDirectory(const std::string& path) const +{ + if (::mkdir(path.c_str(), 0777) == 0) + return true; + return false; +} + +bool sys::OSUnix::isFile(const std::string& path) const +{ + struct stat info; + if (stat(path.c_str(), &info) == -1) + return false; +// throw sys::SystemException("Stat failed"); + return (S_ISREG(info.st_mode)) ? (true) : (false); +} + +bool sys::OSUnix::isDirectory(const std::string& path) const +{ + struct stat info; + if (stat(path.c_str(), &info) == -1) + return false; +// throw sys::SystemException("Stat failed"); + return (S_ISDIR(info.st_mode)) ? (true) : (false); +} + +std::string sys::OSUnix::getCurrentWorkingDirectory() const +{ + char buffer[PATH_MAX]; + if (!getcwd(buffer, PATH_MAX)) + throw sys::SystemException("Getcwd() failed"); + return std::string(buffer); +} + +bool sys::OSUnix::changeDirectory(const std::string& path) const +{ + return chdir(path.c_str()) == 0 ? true : false; +} + +std::string sys::OSUnix::getTempName(const std::string& path, + const std::string& prefix) const +{ + std::string name; +#if defined(_USE_MKSTEMP) || defined(__linux__) || defined(__linux) || defined(linux__) + char fullPath[PATH_MAX + 1]; + strcpy(fullPath, path.c_str()); + strcat(fullPath, "/"); + strcat(fullPath, prefix.c_str()); + strcat(fullPath, "XXXXXX"); + int ret = mkstemp(fullPath); + if (ret == -1) name = ""; + else + { + name = fullPath; + } +#else + char *tempname = tempnam(path.c_str(), prefix.c_str()); + if (tempname == NULL) + name = ""; + else + { + name = tempname; + free(tempname); + } +#endif + return name; +} + +sys::Off_T sys::OSUnix::getSize(const std::string& path) const +{ + return sys::File(path).length(); +} + +sys::Off_T sys::OSUnix::getLastModifiedTime(const std::string& path) const +{ + return sys::File(path).lastModifiedTime(); +} + +void sys::OSUnix::millisleep(int milliseconds) const +{ + usleep(milliseconds * 1000); +} +std::string sys::OSUnix::getDSOSuffix() const +{ + return "so"; +} + +std::string sys::OSUnix::operator[](const std::string& s) const +{ + return getEnv(s); +} + +std::string sys::OSUnix::getEnv(const std::string& s) const +{ + const char* p = getenv(s.c_str()); + if (p == NULL) + throw sys::SystemException( + Ctxt(FmtX("Unable to get unix environment variable %s", + s.c_str()))); + return std::string(p); +} + +void sys::OSUnix::setEnv(const std::string& var, + const std::string& val, + bool overwrite) +{ + int ret; + +#ifdef HAVE_SETENV + ret = setenv(var.c_str(), val.c_str(), overwrite); +#else + // putenv() will overwrite the value if it already exists, so if we don't + // want to overwrite, we do nothing when getenv() indicates the variable's + // already set + if (overwrite || getenv(var.c_str()) == NULL) + { + // putenv() isn't guaranteed to make a copy of the string, so we need + // to allocate it and let it leak. Ugh. + char* const strBuffer = new char[var.length() + 1 + val.length() + 1]; + ::sprintf(strBuffer, "%s=%s", var.c_str(), val.c_str()); + ret = putenv(strBuffer); + } + else + { + ret = 0; + } +#endif + if(ret != 0) + { + throw sys::SystemException(Ctxt( + "Unable to set unix environment variable " + var)); + } +} + +size_t sys::OSUnix::getNumCPUs() const +{ +#ifdef _SC_NPROCESSORS_ONLN + return sysconf(_SC_NPROCESSORS_ONLN); +#else + throw except::NotImplementedException(Ctxt("Unable to get the number of CPUs")); +#endif +} + +void sys::DirectoryUnix::close() +{ + if (mDir) + { + closedir( mDir); + mDir = NULL; + } +} +std::string sys::DirectoryUnix::findFirstFile(const std::string& dir) +{ + // First file is always . on Unix + mDir = ::opendir(dir.c_str()); + if (mDir == NULL) + return ""; + return findNextFile(); +} + +std::string sys::DirectoryUnix::findNextFile() +{ + struct dirent* entry = NULL; + entry = ::readdir(mDir); + if (entry == NULL) + return ""; + return entry->d_name; +} + +#endif diff --git a/modules/c++/sys/source/OSWin32.cpp b/modules/c++/sys/source/OSWin32.cpp new file mode 100644 index 000000000..ffa8b6078 --- /dev/null +++ b/modules/c++/sys/source/OSWin32.cpp @@ -0,0 +1,251 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#if defined(WIN32) + +#include "sys/OSWin32.h" +#include "sys/File.h" + + +std::string sys::OSWin32::getPlatformName() const +{ + OSVERSIONINFO info; + info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + if (!GetVersionEx(&info)) + throw sys::SystemException("While performing GetVersionEx()"); + + std::string platform; + if (info.dwPlatformId == VER_PLATFORM_WIN32s) + { + platform = "Windows on Win32 3.1"; + } + else if (info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) + { + platform = "Windows on Win32 95"; + } + else if (info.dwPlatformId = VER_PLATFORM_WIN32_NT) + { + platform = "Windows on Win32 NT"; + } + else + { + platform = "Unknown Windows OS"; + } + return FmtX("%s: %d.%d [build: %d], %s", platform.c_str(), + info.dwMajorVersion, info.dwMinorVersion, info.dwBuildNumber, + info.szCSDVersion); +} + +std::string sys::OSWin32::getNodeName() const +{ + char buffer[512]; + size_t size = 512; + if (GetComputerName(buffer, (LPDWORD)&size)) + return std::string(buffer, size); + else return std::string("Unknown"); +} + +bool sys::OSWin32::exists(const std::string& path) const +{ + const DWORD what = GetFileAttributes(path.c_str()); + + if (what == INVALID_FILE_ATTRIBUTES) + { + const DWORD errCode = GetLastError(); + if (errCode != ERROR_FILE_NOT_FOUND && errCode != ERROR_PATH_NOT_FOUND) + { + char* err = NULL; + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM, + NULL, errCode, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR) &err, 0, NULL); + throw except::Exception(Ctxt( + "Problem while testing file existence for " + path + + " with Error: " + std::string(err))); + } + return false; + } + + return true; +} + +sys::Pid_T sys::OSWin32::getProcessId() const +{ + return GetCurrentProcessId(); +} + +bool sys::OSWin32::removeFile(const std::string& pathname) const +{ + return (DeleteFile(pathname.c_str() )) ? (true) : (false); +} + +bool sys::OSWin32::removeDirectory(const std::string& pathname) const +{ + return (RemoveDirectory(pathname.c_str())) ? (true): (false); +} + +bool sys::OSWin32::move(const std::string& path, + const std::string& newPath) const +{ + return (MoveFile(path.c_str(), newPath.c_str())) ? (true) : (false); +} + + + +bool sys::OSWin32::isFile(const std::string& path) const +{ + // I'm not 100% sure. So I'm checking + // 1) Exists + // 2) Not Directory + // 3) Not Archive - we aren't doing that... + const DWORD what = GetFileAttributes(path.c_str()); + return (what != INVALID_FILE_ATTRIBUTES && + !(what & FILE_ATTRIBUTE_DIRECTORY)); +} + + +bool sys::OSWin32::isDirectory(const std::string& path) const +{ + const DWORD what = GetFileAttributes(path.c_str()); + return (what != INVALID_FILE_ATTRIBUTES && + (what & FILE_ATTRIBUTE_DIRECTORY)); +} + +bool sys::OSWin32::makeDirectory(const std::string& path) const +{ + return (CreateDirectory(path.c_str(), NULL)) ? (true): (false); +} + +std::string sys::OSWin32::getCurrentWorkingDirectory() const +{ + char buffer[MAX_PATH + 1]; + DWORD where = GetCurrentDirectory(MAX_PATH + 1, buffer); + if (where == 0) + throw sys::SystemException("In getCurrentWorkingDirectory()"); + std::string __str(buffer, where); + return __str; +} + +bool sys::OSWin32::changeDirectory(const std::string& path) const +{ + return SetCurrentDirectory(path.c_str()) ? true : false; +} + +std::string sys::OSWin32::getTempName(const std::string& path, + const std::string& prefix) const +{ + char buffer[MAX_PATH]; + if (GetTempFileName(path.c_str(), + prefix.c_str(), + 0, buffer) == 0) return std::string(""); + return std::string(buffer); +} + +sys::Off_T sys::OSWin32::getSize(const std::string& path) const +{ + return sys::File(path).length(); +} + +sys::Off_T sys::OSWin32::getLastModifiedTime(const std::string& path) const +{ + return sys::File(path).lastModifiedTime(); +} + +void sys::OSWin32::millisleep(int milliseconds) const +{ + Sleep(milliseconds); +} + +std::string sys::OSWin32::getDSOSuffix() const +{ + return "dll"; +} + +std::string sys::OSWin32::operator[](const std::string& s) const +{ + return getEnv(s); +} + + +std::string sys::OSWin32::getEnv(const std::string& s) const +{ + std::string result; + DWORD size = GetEnvironmentVariable(s.c_str(), NULL, 0); + if (size == 0) + throw sys::SystemException(Ctxt(FmtX( + "Unable to get windows environment variable %s", s.c_str()))); + + // If we can use a normal size buffer, lets not bother to malloc + + char *buffer = new char[size + 1]; + DWORD retVal = GetEnvironmentVariable(s.c_str(), buffer, size); + result = buffer; + delete [] buffer; + + return result; +} + +void sys::OSWin32::setEnv(const std::string& var, + const std::string& val, + bool overwrite) +{ + BOOL ret = SetEnvironmentVariable(var.c_str(), val.c_str()); + if(!ret) + throw sys::SystemException(Ctxt(FmtX( + "Unable to set windows environment variable %s", var.c_str()))); +} + +size_t sys::OSWin32::getNumCPUs() const +{ + SYSTEM_INFO info; + GetSystemInfo(&info); + return info.dwNumberOfProcessors; +} + +void sys::DirectoryWin32::close() +{ + if (mHandle != INVALID_HANDLE_VALUE) + ::FindClose(mHandle); + mHandle = INVALID_HANDLE_VALUE; +} + +std::string sys::DirectoryWin32::findFirstFile(const std::string& dir) +{ + std::string plusWC = dir; + plusWC += std::string("\\*"); + mHandle = ::FindFirstFile(plusWC.c_str(), &mFileData); + if (mHandle == INVALID_HANDLE_VALUE) + return ""; + return mFileData.cFileName; +} + +std::string sys::DirectoryWin32::findNextFile() +{ + if (::FindNextFile(mHandle, &mFileData) == 0) + return ""; + return mFileData.cFileName; +} + + +#endif diff --git a/modules/c++/sys/source/Path.cpp b/modules/c++/sys/source/Path.cpp new file mode 100644 index 000000000..3b7552423 --- /dev/null +++ b/modules/c++/sys/source/Path.cpp @@ -0,0 +1,280 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include "sys/Path.h" +#include + +sys::Path::Path() +{ +} + +sys::Path::Path(const Path& parent, std::string child) +{ + mPathName = joinPaths(parent.mPathName, child); +} + +sys::Path::Path(std::string parent, std::string child) +{ + mPathName = joinPaths(parent, child); +} + +sys::Path::Path(std::string pathName) : + mPathName(pathName) +{ +} + +sys::Path& sys::Path::operator=(const sys::Path& path) +{ + if (this != &path) + { + mPathName = path.mPathName; + } + return *this; +} + +sys::Path::Path(const sys::Path& path) +{ + mPathName = path.mPathName; +} + +sys::Path::~Path() +{ +} + +std::string sys::Path::normalizePath(const std::string& path) +{ + std::string osDelimStr(sys::Path::delimiter()); + std::string delimStr = osDelimStr; + + //if it's not a forward slash, add it as one of the options + if (delimStr != "/") + delimStr += "/"; + + //get the drive parts, if any -- we will use the drive later + sys::Path::StringPair driveParts = sys::Path::splitDrive(path); + + std::vector parts = str::Tokenizer(path, delimStr); + + int upCount = 0; + std::deque pathDeque; + for (std::vector::iterator it = parts.begin(); it + != parts.end(); ++it) + { + if (*it == ".") + continue; + else if (*it == "..") + { + //we want to keep the drive, if there is one + if (pathDeque.size() == 1 && (*pathDeque.begin()) + == driveParts.first) + continue; + if (pathDeque.size() > 0) + pathDeque.pop_back(); + else + upCount++; + } + else + pathDeque.push_back(*it); + } + + //use the OS-specific delimiters + std::ostringstream out; + //only apply the beginning up directories if we didn't start at the root (/) + if (!str::startsWith(path, osDelimStr) && !str::startsWith(path, "/") + && driveParts.first.empty()) + { + if (upCount > 0) + out << ".."; + for (int i = 1; i < upCount; ++i) + out << osDelimStr << ".."; + } + + //make sure we don't prepend the drive with a delimiter! + std::deque::iterator it = pathDeque.begin(); + if (!driveParts.first.empty()) + out << *it++; + for (; it != pathDeque.end(); ++it) + out << osDelimStr << *it; + return out.str(); +} + +std::string sys::Path::joinPaths(const std::string& path1, + const std::string& path2) +{ + std::string osDelimStr(sys::Path::delimiter()); + + //check to see if path2 is a root path + if (str::startsWith(path2, osDelimStr) || str::startsWith(path2, "/") + || !sys::Path::splitDrive(path2).first.empty()) + return path2; + + std::ostringstream out; + out << path1; + if (!str::endsWith(path1, osDelimStr) && !str::endsWith(path1, "/")) + out << osDelimStr; + out << path2; + return out.str(); +} + +std::vector sys::Path::separate(const std::string& path) +{ + sys::Path workingPath = path; + std::vector pathList; + sys::Path::StringPair pair; + while ((pair = workingPath.split()).first != workingPath.getPath()) + { + if (!pair.second.empty()) + pathList.push_back(pair.second); + workingPath = pair.first; + } + + std::reverse(pathList.begin(), pathList.end()); + return pathList; +} + +std::string sys::Path::absolutePath(const std::string& path) +{ + std::string osDelimStr(sys::Path::delimiter()); + + sys::Path::StringPair driveParts = sys::Path::splitDrive(path); + if (!str::startsWith(path, osDelimStr) && + !str::startsWith(path, "/") && + driveParts.first.empty()) + { + return sys::Path::normalizePath(sys::Path::joinPaths( + sys::OS().getCurrentWorkingDirectory(), path)); + } + else + { + return sys::Path::normalizePath(path); + } +} + +sys::Path::StringPair sys::Path::splitPath(const std::string& path) +{ + std::string delimStr(sys::Path::delimiter()); + + //if it's not a forward slash, add it as one of the options + if (delimStr != "/") + delimStr += "/"; + + std::string::size_type pos = path.find_last_of(delimStr); + if (pos == std::string::npos) + return sys::Path::StringPair("", path); + else if (!path.empty() && pos == path.length() - 1) + { + // Just call ourselves again without the delimiter + return sys::Path::splitPath(path.substr(0, path.length() - 1)); + } + + std::string::size_type lastRootPos = path.find_last_not_of(delimStr, pos); + std::string root; + if (lastRootPos == std::string::npos) + root = path.substr(0, pos + 1); + else + root = path.substr(0, lastRootPos + 1); + std::string base = path.substr(path.find_first_not_of(delimStr, pos)); + return sys::Path::StringPair(root, base); +} + +sys::Path::StringPair sys::Path::splitExt(const std::string& path) +{ + std::string::size_type pos = path.rfind("."); + if (pos == std::string::npos) + return sys::Path::StringPair(path, ""); + return sys::Path::StringPair(path.substr(0, pos), path.substr(pos)); +} + +std::string sys::Path::basename(const std::string& path, bool removeExt) +{ + std::string baseWithExtension = sys::Path::splitPath(path).second; + if (removeExt) + { + return sys::Path::splitExt(baseWithExtension).first; + } + return baseWithExtension; + +} + +sys::Path::StringPair sys::Path::splitDrive(const std::string& path) +{ +#ifdef WIN32 + std::string::size_type pos = path.find(":"); +#else + std::string::size_type pos = std::string::npos; +#endif + + if (pos == std::string::npos) + return sys::Path::StringPair("", path); + return sys::Path::StringPair(path.substr(0, pos + 1), path.substr(pos + 1)); +} + +const char* sys::Path::delimiter() +{ +#ifdef WIN32 + return "\\"; +#else + return "/"; +#endif +} + +const char* sys::Path::separator() +{ +#ifdef WIN32 + return ";"; +#else + return ":"; +#endif +} + +std::vector sys::Path::list() const +{ + if (!mOS.exists(mPathName) || !mOS.isDirectory(mPathName)) + { + std::ostringstream oss; + oss << "'" << mPathName + << "' does not exist or is not a valid directory"; + throw except::Exception(Ctxt(oss.str())); + } + std::vector listing; + sys::Directory directory; + std::string p = directory.findFirstFile(mPathName.c_str()); + while (!p.empty()) + { + listing.push_back(p); + p = directory.findNextFile(); + } + return listing; +} + +std::ostream& operator<<(std::ostream& os, const sys::Path& path) +{ + os << path.getPath().c_str(); + return os; +} +std::istream& operator>>(std::istream& is, sys::Path& path) +{ + std::string str; + is >> str; + path.reset(str); + return is; +} diff --git a/modules/c++/sys/source/ProcessUnix.cpp b/modules/c++/sys/source/ProcessUnix.cpp new file mode 100644 index 000000000..71d0e86bf --- /dev/null +++ b/modules/c++/sys/source/ProcessUnix.cpp @@ -0,0 +1,76 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#if !defined(WIN32) +#include "sys/ProcessUnix.h" +#include + +void sys::ProcessUnix::start() +{ + pid_t lPid = fork(); + if (lPid == sys::ProcessUnix::PROCESS_CREATE_FAILED) + { + dbg_printf("Invalid pid!\n"); + exit(EXIT_FAILURE); + } + if (lPid == sys::ProcessUnix::THE_CHILD) + { + // Run the runnable that we pulled off the queue + mTarget->run(); + dbg_printf("Call succeeded\n"); + exit(EXIT_SUCCESS); + } + else // lPid == THE_PARENT + { + dbg_printf("In parent and child pid is: %d\n", lPid); + mChildProcessID = lPid; + return ; + } + +} + + +void sys::ProcessUnix::waitFor() +{ + dbg_printf("Waiting\n"); + int status; + //pid_t pid = wait(&status); + //assert(pid == mChildProcessID); + int options = 0; + int whatExited = waitpid(mChildProcessID, &status, options); + if (WIFEXITED(status)) + { + dbg_printf("Exited normally.\n"); + } + if (WIFSIGNALED(status)) + { + dbg_printf("Uncaught signal.\n"); + } + if (WIFSTOPPED(status)) + { + dbg_printf("Stopped.\n"); + } + dbg_printf("Finished waiting on pid: %d\n", mChildProcessID); + assert(whatExited == mChildProcessID); +} +#endif diff --git a/modules/c++/sys/source/ProcessWin32.cpp b/modules/c++/sys/source/ProcessWin32.cpp new file mode 100644 index 000000000..1d37d7443 --- /dev/null +++ b/modules/c++/sys/source/ProcessWin32.cpp @@ -0,0 +1,29 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#if defined(WIN32) + +#include "sys/Process.h" +#include "sys/Thread.h" + +#endif diff --git a/modules/c++/sys/source/ReadWriteMutex.cpp b/modules/c++/sys/source/ReadWriteMutex.cpp new file mode 100644 index 000000000..d9faa0304 --- /dev/null +++ b/modules/c++/sys/source/ReadWriteMutex.cpp @@ -0,0 +1,63 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#if defined(_REENTRANT) && !defined(__APPLE_CC__) +#include "sys/ReadWriteMutex.h" + +void sys::ReadWriteMutex::lockRead() +{ + // Count up one reader + mSem.wait(); +} +void sys::ReadWriteMutex::unlockRead() +{ + // Count down one reader + mSem.signal(); +} + +void sys::ReadWriteMutex::lockWrite() +{ + // Need to lock so other writers cannot try + // waiting + mMutex.lock(); + // Count the semaphore all the way up so we + // know that any call to lockRead will have to + // wait for a signal + for(int i=0; i < mMaxReaders; ++i) + { + mSem.wait(); + } + mMutex.unlock(); +} + +void sys::ReadWriteMutex::unlockWrite() +{ + // Signal so that readers can resume reading + for(int i=0; i < mMaxReaders; ++i) + { + mSem.signal(); + } +} + +#endif // _REENTRANT + diff --git a/modules/c++/sys/source/SemaphoreIrix.cpp b/modules/c++/sys/source/SemaphoreIrix.cpp new file mode 100644 index 000000000..9d1e4aeda --- /dev/null +++ b/modules/c++/sys/source/SemaphoreIrix.cpp @@ -0,0 +1,64 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#if defined(__sgi) && defined(_REENTRANT) && !defined(__POSIX) +#include +#include "sys/SemaphoreIrix.h" + + +sys::SemaphoreIrix::SemaphoreIrix(unsigned int count) +{ + if (!sys::SyncFactoryIrix().createSemaphore(*this, count)) + throw SystemException("Semaphore initialization failed"); +} + +sys::SemaphoreIrix::~SemaphoreIrix() +{ + dbg_printf("~SemaphoreIrix()\n"); + sys::SyncFactoryIrix().destroySemaphore(*this); + dbg_printf("done.\n"); +} + +void sys::SemaphoreIrix::wait() +{ + dbg_printf("SemaphoreIrix::wait()\n"); + if (!sys::SyncFactoryIrix().waitSemaphore(*this)) + throw SystemException("Semaphore wait failed"); + +} + +void sys::SemaphoreIrix::signal() +{ + dbg_printf("SemaphoreIrix::signal()\n"); + if (!sys::SyncFactoryIrix().signalSemaphore(*this)) + throw SystemException("Semaphore signal failed"); +} + +usema_t*& sys::SemaphoreIrix::getNative() +{ + // We don't actually use this, but SemaphoreIrix uses usema_t* as its template.. + return (usema_t*) NULL; +} + +#endif // __sgi && _REENTRANT && !__POSIX + diff --git a/modules/c++/sys/source/SemaphorePosix.cpp b/modules/c++/sys/source/SemaphorePosix.cpp new file mode 100644 index 000000000..d10285f0e --- /dev/null +++ b/modules/c++/sys/source/SemaphorePosix.cpp @@ -0,0 +1,56 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#if defined(__POSIX) && defined(_REENTRANT) && !defined(__APPLE_CC__) +#include +#include "sys/SemaphorePosix.h" + +sys::SemaphorePosix::SemaphorePosix(unsigned int count) +{ + sem_init(&mNative, 0, count); +} + +sys::SemaphorePosix::~SemaphorePosix() +{ + sem_destroy(&mNative); +} + +void sys::SemaphorePosix::wait() +{ + if (sem_wait(&mNative) != 0) + throw sys::SystemException("Semaphore wait failed"); +} + +void sys::SemaphorePosix::signal() +{ + if (sem_post(&mNative) != 0) + throw sys::SystemException("Semaphore signal failed"); +} + +sem_t& sys::SemaphorePosix::getNative() +{ + return mNative; +} + +#endif + diff --git a/modules/c++/sys/source/SemaphoreSolaris.cpp b/modules/c++/sys/source/SemaphoreSolaris.cpp new file mode 100644 index 000000000..5ee9ed92c --- /dev/null +++ b/modules/c++/sys/source/SemaphoreSolaris.cpp @@ -0,0 +1,56 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#if defined(__sun) && defined(_REENTRANT) && !defined(__POSIX) +#include +#include "sys/SemaphoreSolaris.h" + +sys::SemaphoreSolaris::SemaphoreSolaris(unsigned int count) +{ + sema_init(&mNative, count, USYNC_THREAD, NULL); +} + +sys::SemaphoreSolaris::~SemaphoreSolaris() +{ + sema_destroy(&mNative); +} + +void sys::SemaphoreSolaris::wait() +{ + if (sema_wait(&mNative) != 0) + throw sys::SystemException("Semaphore wait failed"); +} + +void sys::SemaphoreSolaris::signal() +{ + if (sema_post(&mNative) != 0) + throw sys::SystemException("Semaphore signal failed"); +} + +sema_t& sys::SemaphoreSolaris::getNative() +{ + return mNative; +} + +#endif + diff --git a/modules/c++/sys/source/SemaphoreWin32.cpp b/modules/c++/sys/source/SemaphoreWin32.cpp new file mode 100644 index 000000000..9de81065c --- /dev/null +++ b/modules/c++/sys/source/SemaphoreWin32.cpp @@ -0,0 +1,65 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#if defined(WIN32) && defined(_REENTRANT) + +#if !defined(USE_NSPR_THREADS) && !defined(__POSIX) + +#include "sys/SemaphoreWin32.h" + +sys::SemaphoreWin32::SemaphoreWin32(unsigned int count) +{ + mNative = CreateSemaphore(NULL, count, MAX_COUNT, NULL); + if (mNative == NULL) + throw sys::SystemException("CreateSempaphore Failed"); + +} + +void sys::SemaphoreWin32::wait() +{ + DWORD waitResult = WaitForSingleObject( + mNative, + INFINITE); + if (waitResult != WAIT_OBJECT_0) + { + throw sys::SystemException("Semaphore wait failed"); + } +} + +void sys::SemaphoreWin32::signal() +{ + if (!ReleaseSemaphore(mNative, + 1, + NULL) ) + { + throw sys::SystemException("Semaphore signal failed"); + } +} + +HANDLE& sys::SemaphoreWin32::getNative() +{ + return mNative; +} + +#endif +#endif diff --git a/modules/c++/sys/source/StopWatch.cpp b/modules/c++/sys/source/StopWatch.cpp new file mode 100644 index 000000000..ea2c1d043 --- /dev/null +++ b/modules/c++/sys/source/StopWatch.cpp @@ -0,0 +1,153 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#include "sys/StopWatch.h" + +sys::RealTimeStopWatch::RealTimeStopWatch():mStartTime(0),mTimePaused(0),mPauseStartTime(0),mPaused(false) +{ +} + +sys::RealTimeStopWatch::~RealTimeStopWatch() +{ +} + +double sys::RealTimeStopWatch::start() +{ + sys::LocalDateTime now; + double nowInMillis = now.getTimeInMillis(); + + // If we are in a paused state + if(mPaused) + { + // accumulate the time we have been paused + mTimePaused += nowInMillis - mPauseStartTime; + mPaused = false; + } // else set the start time to right now + else + mStartTime = nowInMillis; + + // return the current time + return nowInMillis; +} + +double sys::RealTimeStopWatch::stop() +{ + sys::LocalDateTime now; + double nowInMillis = now.getTimeInMillis(); + // If in a paused state, accumulate paused time + if(mPaused) + { + mTimePaused += (nowInMillis - mPauseStartTime); + mPaused = false; + } + // If we have been started then calculate stop time, + // otherwise don't bother + if(mStartTime != 0) + { + double elapsed = (nowInMillis - mStartTime - mTimePaused); + //mStartTime = 0; + return elapsed; + } + return 0; +} + +double sys::RealTimeStopWatch::pause() +{ + // If not already paused, set it to be so and the + // pause start time to be now + if(!mPaused) + { + sys::LocalDateTime now; + mPauseStartTime = now.getTimeInMillis(); + mPaused = true; + } + return mPauseStartTime; +} + +void sys::RealTimeStopWatch::clear() +{ + // reset the stopwatch + mStartTime = 0; + mPauseStartTime = 0; + mTimePaused = 0; + mPaused = false; +} + +sys::CPUStopWatch::CPUStopWatch():mStartTime(-1),mPauseStartTime(0),mTimePaused(0),mPaused(false) +{ + mClocksPerMillis = CLOCKS_PER_SEC/1000; +} + +sys::CPUStopWatch::~CPUStopWatch() +{ +} + +double sys::CPUStopWatch::start() +{ + clock_t now = clock(); + // If we're in a paused state, accumulate the paused time + if(mPaused) + { + mTimePaused += (now - mPauseStartTime); + mPaused = false; + } + else + mStartTime = now; + + return ((double)now/mClocksPerMillis); +} + +double sys::CPUStopWatch::stop() +{ + clock_t end = clock(); + // If in paused state, accumulate paused time before stopping + if(mPaused) + { + mTimePaused += (end - mPauseStartTime); + mPaused = false; + } + // If start time was never set (or reset) then don't bother calculating elapsed time + if(mStartTime != -1) + return ((double)(end - mStartTime - mTimePaused)/mClocksPerMillis); + else + return 0; +} + +double sys::CPUStopWatch::pause() +{ + if(!mPaused) + { + mPauseStartTime = clock(); + mPaused = true; + } + return ((double)mPauseStartTime/mClocksPerMillis); +} + +void sys::CPUStopWatch::clear() +{ + // 0 is valid for clock() so reset start to -1 + mStartTime = -1; + mPauseStartTime = 0; + mTimePaused = 0; + mPaused = false; +} diff --git a/modules/c++/sys/source/SyncFactoryIrix.cpp b/modules/c++/sys/source/SyncFactoryIrix.cpp new file mode 100644 index 000000000..de90e11aa --- /dev/null +++ b/modules/c++/sys/source/SyncFactoryIrix.cpp @@ -0,0 +1,210 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +# if defined(__sgi) && defined(_REENTRANT) && !defined(__POSIX) +#include + +#include "sys/SyncFactoryIrix.h" +#include "sys/MutexIrix.h" +#include "sys/SemaphoreIrix.h" +#include "sys/ThreadIrix.h" +#include "sys/ConditionVarIrix.h" + +sys::SyncFactoryIrix::SyncImplIrix* sys::SyncFactoryIrix::mImpl = NULL; +sys::SyncFactoryIrix::SyncImplIrix::SyncImplIrix() : mRef(0), mArena(NULL) +{ + // NOTE: SIGUSR1 is used in the Irix conditional + // variable, and needs to be blocked by the process. + // If it isn't blocked, then the threads may terminate + // prematurely if they are not waiting on the signal + // when the signal occurs. + HERE(); + sigset_t lSignalSet; + //sigset_t lSignalInfo; + + sigemptyset(&lSignalSet); + sigaddset(&lSignalSet, SIGUSR1); + sigprocmask(SIG_BLOCK, &lSignalSet, NULL); + + + // Set maximum number of sharing processes, default=8 + usconfig(CONF_INITUSERS, 128); + + // Enable autogrow options for arena + usconfig(CONF_AUTOGROW, 1); // Default=enabled, but set anyways + usconfig(CONF_AUTORESV, 1); // Only valid if using /dev/zero + + // Create shared memory arena using logical swap pool + mArena = usinit( "/dev/zero" ); + + assert( mArena ); + EVAL( mArena); + + mGuard = new ulock_t; + *mGuard = usnewlock(mArena); + if (*mGuard == NULL) + { + delete mGuard; + mGuard = NULL; + } + + +} + +sys::SyncFactoryIrix::SyncImplIrix::~SyncImplIrix() +{ + dbg_ln("Destructing the SyncImpl"); + + dbg_ln("Removing the guard from the arena"); + usfreelock(*mGuard, mArena); + dbg_ln("Deleting the guard"); + delete mGuard; + dbg_ln("Detaching the arena"); + usdetach(mArena); + + mArena = NULL; + dbg_ln("Done destructing the SyncImpl"); +} + +bool sys::SyncFactoryIrix::SyncImplIrix::startThread(sys::ThreadIrix& t) +{ + dbg_ln("Starting thread"); + t.getNative() = sproc(sys::ThreadIrix::__start, + PR_SADDR | PR_SFDS | PR_SDIR | PR_SUMASK, + &t); + EVAL(t.getNative()); + if (t.getNative() <= 0) + { + dbg_ln("sproc() call failed!"); + return false; + + } + return true; +} +bool sys::SyncFactoryIrix::SyncImplIrix::killThread(sys::ThreadIrix& t) +{ + dbg_ln("Killing thread"); + if ( ::kill(t.getNative(), SIGKILL) == 0 ) + { + t.setIsRunning(false); + return true; + } + dbg_ln("Thread kill() failed"); + return false; +} +bool sys::SyncFactoryIrix::SyncImplIrix::createLock(sys::MutexIrix& mutex) +{ + dbg_ln("Creating the lock"); + ussetlock(*mGuard); + mutex.getNative() = new ulock_t; + *(mutex.getNative()) = usnewlock(mArena); + if (*(mutex.getNative()) == NULL) + { + dbg_ln("Lock creation failed"); + delete mutex.getNative(); + mutex.getNative() = NULL; + return false; + } + TRACE(mRef++); + EVAL(mRef); + usunsetlock(*mGuard); + dbg_ln("Successfully created lock"); + return true; +} + +bool sys::SyncFactoryIrix::SyncImplIrix::destroyLock(sys::MutexIrix& mutex) +{ + dbg_ln("Destroying the lock"); + ussetlock(*mGuard); + EVAL(mArena); + + EVAL( &mutex ); + EVAL( mutex.getNative() ); + TRACE( usfreelock(*(mutex.getNative()), mArena) ); + TRACE( delete mutex.getNative() ); + mutex.getNative() = NULL; + + TRACE(mRef--); + EVAL(mRef); + usunsetlock(*mGuard); + return true; + +} + +bool sys::SyncFactoryIrix::SyncImplIrix::setLock(sys::MutexIrix& mutex) +{ + dbg_ln("Setting the lock"); + return ( ussetlock( *(mutex.getNative() ) ) == 1 ); +} + +bool sys::SyncFactoryIrix::SyncImplIrix::unsetLock(sys::MutexIrix& mutex) +{ + dbg_ln("Unsetting the lock"); + + return ( usunsetlock( *(mutex.getNative() ) ) == 0 ); +} + + +bool sys::SyncFactoryIrix::SyncImplIrix::waitSemaphore(sys::SemaphoreIrix& sema) +{ + dbg_ln("Waiting for semaphore"); + return ( uspsema( sema.getNative() ) == 1 ); +} + +bool sys::SyncFactoryIrix::SyncImplIrix::signalSemaphore(sys::SemaphoreIrix& sema) +{ + dbg_ln("Signalling semaphore"); + return ( usvsema( sema.getNative() ) == 0 ); +} + +bool sys::SyncFactoryIrix::SyncImplIrix::createSemaphore(sys::SemaphoreIrix& sema, + unsigned int count) +{ + dbg_ln("Creating semaphore"); + ussetlock(*mGuard); + sema.getNative() = usnewsema(mArena, count); + if (!sema.getNative()) + { + dbg_ln("Semaphore creation failed!"); + return false; + } + TRACE(mRef++); + EVAL(mRef); + usunsetlock(*mGuard); + dbg_ln("Successfully created semaphore"); + return true; +} + +bool sys::SyncFactoryIrix::SyncImplIrix::destroySemaphore(sys::SemaphoreIrix& sema) +{ + dbg_ln("Destroying semaphore"); + ussetlock(*mGuard); + usfreesema(sema.getNative(), mArena); + + TRACE(mRef--); + EVAL(mRef); + usunsetlock(*mGuard); + return true; +} +#endif + diff --git a/modules/c++/sys/source/ThreadIrix.cpp b/modules/c++/sys/source/ThreadIrix.cpp new file mode 100644 index 000000000..71ce6fcc5 --- /dev/null +++ b/modules/c++/sys/source/ThreadIrix.cpp @@ -0,0 +1,55 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#if defined(__sgi) && defined(_REENTRANT) && !defined(__POSIX) +#include "sys/ThreadIrix.h" + +// void sys::ThreadIrix::start() +// { +// sys::SyncFactoryIrix()->startThread(*this); +// } +// bool sys::ThreadIrix::kill() +// { +// return sys::SyncFactoryIrix()->killThread(*this); +// } + +void sys::ThreadIrix::join() +{ + dbg_printf("Joining on thread\n"); + int lStatus; + do + { + waitpid(mNative, &lStatus, 0); + dbg_printf("Waiting on thread [%d]\n", mNative); + } + while ( WIFEXITED(lStatus) == 0 ); + dbg_printf("Done joining on thread\n"); +} + +void sys::ThreadIrix::yield() +{ + dbg_printf("ThreadIrix::yield()\n"); + sginap(0); +} +#endif + diff --git a/modules/c++/sys/source/ThreadNSPR.cpp b/modules/c++/sys/source/ThreadNSPR.cpp new file mode 100644 index 000000000..1acc7bf35 --- /dev/null +++ b/modules/c++/sys/source/ThreadNSPR.cpp @@ -0,0 +1,67 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +# if defined(USE_NSPR_THREADS) +#include "sys/ThreadNSPR.h" +void sys::ThreadNSPR::__start(void *v) +{ + STANDARD_START_CALL(ThreadNSPR, v); +} +void sys::ThreadNSPR::start() +{ + + PRThreadType type = (getLevel() == sys::ThreadNSPR::KERNEL_LEVEL) ? + (PR_SYSTEM_THREAD) : (PR_USER_THREAD); + + PRThreadScope scope = (mIsLocal) ? (PR_LOCAL_THREAD) : + (PR_GLOBAL_THREAD); + + PRThreadPriority priority; + if (getPriority() == sys::ThreadNSPR::NORMAL_PRIORITY) + priority = PR_PRIORITY_NORMAL; + else if (getPriority() == sys::ThreadNSPR::MAXIMUM_PRIORITY) + priority = PR_PRIORITY_HIGH; + else if (getPriority() == sys::ThreadNSPR::MINIMUM_PRIORITY) + priority = PR_PRIORITY_LOW; + mNative = PR_CreateThread(type, + (void (*)(void *))this->__start, + this, + priority, + scope, + PR_JOINABLE_THREAD, + 0); +} + +void sys::ThreadNSPR::join() +{ + if (!PR_JoinThread(mNative)) + throw sys::SystemException("join()"); +} + +void sys::ThreadNSPR::yield() +{ + PR_Sleep(PR_INTERVAL_NO_WAIT); +} + +# endif + diff --git a/modules/c++/sys/source/ThreadPosix.cpp b/modules/c++/sys/source/ThreadPosix.cpp new file mode 100644 index 000000000..b3cea8864 --- /dev/null +++ b/modules/c++/sys/source/ThreadPosix.cpp @@ -0,0 +1,106 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#include "sys/ThreadPosix.h" + +#if defined(__POSIX) && defined(_REENTRANT) + +#ifdef WIN32 +# define SIGKILL 0 +#endif +void sys::ThreadPosix::start() +{ + + if (getLevel() != DEFAULT_LEVEL) + { + throw sys::SystemException("Cannot determine upfront wheteher pthread threads are implemented using kernel or user level threads. Set the level to DEFAULT_LEVEL"); + } + + if (getPriority() != NORMAL_PRIORITY) + { + sched_param sp; + + if (getPriority() == MAXIMUM_PRIORITY) + sp.sched_priority = sched_get_priority_max(SCHED_OTHER); + + else if (getPriority() == MINIMUM_PRIORITY) + sp.sched_priority = sched_get_priority_min(SCHED_OTHER); + + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setschedparam(&attr, + &sp); + + if (::pthread_create(&mNative, + &attr, + (void *(*)(void *))this->__start, + this) != 0) + throw sys::SystemException("pthread_create()"); + pthread_attr_destroy(&attr); + } + else + { + if (::pthread_create(&mNative, + NULL, + (void *(*)(void *))this->__start, + this) != 0) + throw sys::SystemException("pthread_create()"); + } +} +void *sys::ThreadPosix::__start(void *v) +{ + STANDARD_START_CALL(ThreadPosix, v); + /* + sys::Runnable *runnable = + static_cast(v); + + runnable->run(); + + // If the pointers don't match, then the runnable is not 'this' + // and therefore it's ok to delete the runnable. + delete runnable; + */ + + pthread_exit(NULL); + return NULL; +} + +void sys::ThreadPosix::kill() +{ + if (pthread_kill(mNative, SIGKILL) != 0) + { + throw sys::SystemException("pthread_kill()"); + } + setIsRunning(false); +} +void sys::ThreadPosix::join() +{ + if (::pthread_join(mNative, NULL) != 0) + throw sys::SystemException("pthread_join()"); +} +void sys::ThreadPosix::yield() +{ + ::sched_yield(); +} + +#endif diff --git a/modules/c++/sys/source/ThreadSolaris.cpp b/modules/c++/sys/source/ThreadSolaris.cpp new file mode 100644 index 000000000..164c06ddf --- /dev/null +++ b/modules/c++/sys/source/ThreadSolaris.cpp @@ -0,0 +1,87 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#if defined(__sun) && defined(_REENTRANT) && !defined(__POSIX) +#include "sys/ThreadSolaris.h" +#include "sys/Dbg.h" + + +void sys::ThreadSolaris::start() +{ + + long flags = 0; + if (getLevel() == KERNEL_LEVEL ) + flags |= THR_BOUND; + + dbg_printf("Starting thread and is kernel? [%d]\n", + getLevel() == KERNEL_LEVEL); + // \todo Kernel level + + int p = thr_create(NULL, + 0, + __sys_ThreadSolaris_start, + this, + flags, + &mNative); + if (p != 0) + { + std::string message = "thr_create failed: "; + if ( p == EAGAIN ) message += "EAGAIN"; + else if ( p == EINVAL ) message += "EINVAL"; + else if ( p == ENOMEM ) message += "ENOMEM"; + throw sys::SystemException(message); + } +} +extern "C" void *__sys_ThreadSolaris_start(void *v) +{ + dbg_printf("Beginning __start()\n"); + STANDARD_START_CALL(ThreadSolaris, v); + dbg_printf("Finishing __start()\n"); + return NULL; + +} + +void sys::ThreadSolaris::kill() +{ + dbg_printf("Killing thread\n"); + if ( thr_kill(mNative, SIGKILL) != 0) + { + throw sys::SystemException("thr_kill()"); + } + setIsRunning(false); +} + +void sys::ThreadSolaris::join() +{ + dbg_printf("Joining thread\n"); + if (::thr_join(mNative, NULL, NULL) != 0 ) + throw sys::SystemException("thr_join()"); +} + +void sys::ThreadSolaris::yield() +{ + dbg_printf("Yielding thread\n"); + ::thr_yield(); +} + +#endif diff --git a/modules/c++/sys/source/ThreadWin32.cpp b/modules/c++/sys/source/ThreadWin32.cpp new file mode 100644 index 000000000..becdbdaab --- /dev/null +++ b/modules/c++/sys/source/ThreadWin32.cpp @@ -0,0 +1,64 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#if defined(WIN32) && defined(_REENTRANT) +#if !defined(USE_NSPR_THREADS) && !defined(__POSIX) +#include "sys/ThreadWin32.h" + + +sys::ThreadWin32::~ThreadWin32() +{ + if (mNative) + { + CloseHandle(mNative); + } + +} + +void sys::ThreadWin32::start() +{ + DWORD threadId; + + mNative = __CREATETHREAD(NULL, + 0, + __start, + (void*)this, + 0, + &threadId); + if (mNative == NULL) + throw sys::SystemException("Thread creation failed"); + + +} + + +void sys::ThreadWin32::join() +{ + if (WaitForSingleObject(mNative, INFINITE) == WAIT_FAILED) + throw sys::SystemException("Thread join failed"); + +} + +#endif // Not using another package + +#endif // We're on windows diff --git a/modules/c++/sys/source/UTCDateTime.cpp b/modules/c++/sys/source/UTCDateTime.cpp new file mode 100755 index 000000000..a1793dba8 --- /dev/null +++ b/modules/c++/sys/source/UTCDateTime.cpp @@ -0,0 +1,211 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include "sys/UTCDateTime.h" + +#include "sys/Conf.h" +#include "except/Exception.h" +#include "str/Convert.h" +#include "str/Manip.h" + +#include + + +namespace +{ + +// These constants and functions were taken from the NRT DateTime.c implementation + +const long UNIX_EPOCH_YEAR(1970); // EPOCH = Jan 1 1970 00:00:00 +const double SECS_IN_MIN(60.0); +const double SECS_IN_HOUR(60.0 * SECS_IN_MIN); +const double SECS_IN_DAY(24.0 * SECS_IN_HOUR); + +// At the end of each month, the total number of days so far in the year. +// Index 0 is for non-leap years, index 1 is for leap years +const int CUMULATIVE_DAYS_PER_MONTH[2][12] = +{ + {31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365}, + {31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366} +}; + +// The number of days in a year. Index 0 is for non-leap years, index 1 is +// for leap years +const int DAYS_PER_YEAR[2] = {365, 366}; + +// Returns the appropriate index into CUMULATIVE_DAYS_PER_MONTH based on +// whether 'year' is a leap year or not +int yearIndex(int year) +{ + return (!(year % 4) && ((year % 100) || !(year % 400))); +} + +// Returns the # of full days so far in the year +// 'month' and 'dayOfMonth' are 1-based +// So, getNumFullDaysInYearSoFar(2000, 1, 1) = 0 +// getNumFullDaysInYearSoFar(2000, 1, 2) = 1 +// getNumFullDaysInYearSoFar(2000, 2, 1) = 31 +int getNumFullDaysInYearSoFar(int year, int month, int dayOfMonth) +{ + /* The number of days for all the full months so far */ + int numFullDays = (month > 1) ? + CUMULATIVE_DAYS_PER_MONTH[yearIndex(year)][month - 2] : + 0; + + /* The number of full days in this month so far */ + numFullDays += dayOfMonth - 1; + return numFullDays; +} + +} + +const char sys::UTCDateTime::DEFAULT_DATETIME_FORMAT[] = "%Y-%m-%dT%H:%M:%SZ"; + + +void sys::UTCDateTime::toMillis() +{ + if (mSecond < 0.0 || mSecond >= 60.0 || + mMinute < 0 || mMinute > 59 || + mHour < 0 || mHour > 23 || + mDayOfMonth < 1 || mDayOfMonth > 31 || + mMonth < 1 || mMonth > 12 || + mYear < 1970 || mYear > 2037) + { + mTimeInMillis = 0.0; + mDayOfYear = mDayOfWeek = 0; + return; + } + + /* Essentially we are implementing a simplified variant of mktime() here. + * Implementation loosely based on + * http://www.raspberryginger.com/jbailey/minix/html/mktime_8c-source.html + * The problem with mktime() is that it expects local time and we are in + * GMT. Note that we can't just call mktime(), then look at the + * difference between localtime() and gmtime() and offset the result by + * that amount because this approach can't reliably take daylight savings + * time into account. Another option would be to trick mktime() by + * setting the TZ environment variable to UTC, but this wouldn't be + * reentrant. + * It is very unfortunate that there's no POSIX standard function similar + * to mktime() that allows you to pass in the timezone you want. + */ + long numDaysThisYear = getNumFullDaysInYearSoFar(mYear, mMonth, mDayOfMonth); + long numDaysSinceEpoch = 0; + + /* Count up the # of days for all the years prior to this one + * TODO: This could be implemented more efficiently - see reference + * implementation above. */ + for (int i = UNIX_EPOCH_YEAR; i < mYear; ++i) + { + numDaysSinceEpoch += DAYS_PER_YEAR[yearIndex(i)]; + } + numDaysSinceEpoch += numDaysThisYear; + + mTimeInMillis = (mSecond + mMinute * SECS_IN_MIN + + mHour * SECS_IN_HOUR + numDaysSinceEpoch * SECS_IN_DAY) * 1000.0; + mDayOfYear = numDaysThisYear + 1; + + /* January 1, 1970 was a Thursday (5) */ + mDayOfWeek = (numDaysSinceEpoch + 5) % 7; +} + +void sys::UTCDateTime::getTime(time_t numSecondsSinceEpoch, tm& t) const +{ + // Would like to use the reentrant version. If we don't have one, cross + // our fingers and hope the regular function actually is reentrant + // (supposedly this is the case on Windows). +#ifdef HAVE_GMTIME_R + if (::gmtime_r(&numSecondsSinceEpoch, &t) == NULL) + { + int const errnum = errno; + throw except::Exception(Ctxt("gmtime_r() failed (" + + std::string(::strerror(errnum)) + ")")); + } +#else + tm const * const gmTimePtr = ::gmtime(&numSecondsSinceEpoch); + if (gmTimePtr == NULL) + { + int const errnum = errno; + throw except::Exception(Ctxt("gmtime failed (" + + std::string(::strerror(errnum)) + ")")); + } + t = *gmTimePtr; +#endif +} + +sys::UTCDateTime::UTCDateTime() +{ + setNow(); + toMillis(); +} + +sys::UTCDateTime::UTCDateTime(int hour, int minute, double second) +{ + setNow(); + + mHour = hour; + mMinute = minute; + mSecond = second; + + toMillis(); +} + +sys::UTCDateTime::UTCDateTime(int year, int month, int day) +{ + setNow(); + + mYear = year; + mMonth = month; + mDayOfMonth = day; + + toMillis(); + fromMillis(); +} + +sys::UTCDateTime::UTCDateTime(int year, int month, int day, + int hour, int minute, double second) +{ + setNow(); + + mYear = year; + mMonth = month; + mDayOfMonth = day; + mHour = hour; + mMinute = minute; + mSecond = second; + + toMillis(); + fromMillis(); +} + +sys::UTCDateTime::UTCDateTime(double timeInMillis) +{ + mTimeInMillis = timeInMillis; + + fromMillis(); +} + +std::string sys::UTCDateTime::format() const +{ + return format(DEFAULT_DATETIME_FORMAT); +} + diff --git a/modules/c++/sys/tests/AlignedAllocTest.cpp b/modules/c++/sys/tests/AlignedAllocTest.cpp new file mode 100644 index 000000000..f56bc0a2c --- /dev/null +++ b/modules/c++/sys/tests/AlignedAllocTest.cpp @@ -0,0 +1,75 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include + +#include +#include +#include +#include + +int main(int argc, char** argv) +{ + try + { + if (argc != 2) + { + std::cerr << "Usage: " << sys::Path::basename(argv[0]) + << " <# bytes to allocate>\n\n"; + return 1; + } + const size_t numBytes(str::toType(argv[1])); + + // Allocate an aligned buffer + void* const ptr = sys::alignedAlloc(numBytes); + + // Confirm it's a multiple of 16 + bool const isAligned(reinterpret_cast(ptr) % 16 == 0); + + sys::alignedFree(ptr); + + if (!isAligned) + { + std::cerr << "Error: buffer " << ptr + << " isn't aligned as expected!\n"; + return 1; + } + } + catch (const std::exception& ex) + { + std::cerr << "Caught std::exception: " << ex.what() << std::endl; + return 1; + } + catch (const except::Exception& ex) + { + std::cerr << "Caught except::exception: " << ex.getMessage() + << std::endl; + return 1; + } + catch (...) + { + std::cerr << "Caught unknown exception\n"; + return 1; + } + + return 0; +} diff --git a/modules/c++/sys/tests/DLLTest.cpp b/modules/c++/sys/tests/DLLTest.cpp new file mode 100644 index 000000000..f80be52f8 --- /dev/null +++ b/modules/c++/sys/tests/DLLTest.cpp @@ -0,0 +1,64 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include +#include +#include +#include +using namespace except; +using namespace sys; + +typedef bool (*HOOK_FN)(void); + +int main(int argc, char** argv) +{ + if (argc != 3) + { + die_printf( + "Usage: %s \n\twhere hook=bool (void*)(void)\n", + argv[0]); + } + // Ok, we got past the initial hurdle, now lets + // try and load the thing + try + { + std::string dsoPath = argv[1]; + std::string hook = argv[2]; + + DLL dso(dsoPath); + + HOOK_FN theHook = (HOOK_FN) dso.retrieve(hook); + + // Call the hook + if (!theHook()) + { + throw Exception(Ctxt("The hook failed!")); + } + + } + catch (Throwable& ex) + { + std::cout << ex.toString() << std::endl; + } + +} + diff --git a/modules/c++/sys/tests/DateTimeTest.cpp b/modules/c++/sys/tests/DateTimeTest.cpp new file mode 100644 index 000000000..ac12f6de3 --- /dev/null +++ b/modules/c++/sys/tests/DateTimeTest.cpp @@ -0,0 +1,101 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include +#include +#include +#include "sys/StopWatch.h" +#include "sys/LocalDateTime.h" +#include "sys/UTCDateTime.h" + +using namespace sys; + +int main(int argc, char **argv) +{ + try + { + sys::LocalDateTime now; + std::cout << "Today is: " << now.getMonth() << "/" + << now.getDayOfMonth() << "/" << now.getYear() << std::endl; + std::cout << "Time is: " << now.getHour() << ":" << now.getMinute() + << ":" << std::setprecision(50) << now.getSecond() << std::endl; + if (now.getDST()) + std::cout << "Daylight Savings Time is in effect" << std::endl; + std::cout << "formatted: " << now.format() << std::endl; + + sys::UTCDateTime gmnow; + std::cout << "Today (UTC) is: " << gmnow.getMonth() << "/" + << gmnow.getDayOfMonth() << "/" << gmnow.getYear() << std::endl; + std::cout << "Time (UTC) is: " << gmnow.getHour() << ":" + << gmnow.getMinute() << ":" << std::setprecision(50) + << gmnow.getSecond() << std::endl; + std::cout << "formatted: " << gmnow.format() << std::endl; + + sys::RealTimeStopWatch sw; + sys::CPUStopWatch csw; + //std::cout << "CPS: " << CLOCKS_PER_SEC << std::endl; + std::cout << "clock(): " << clock() / CLOCKS_PER_SEC << std::endl; + std::cout << "time(): " << time(NULL) << std::endl; + std::cout << "RTStart: " << sw.start() << std::endl; + std::cout << "CStart: " << csw.start() << std::endl; + int x = 0; + for (int i = 0; i < 1000000000; ++i) + { + x = 1 * 2 * 3; + } + std::cout << "Finish Loop 1" << std::endl; + sw.pause(); + csw.pause(); + for (int i = 0; i < 1000000000; ++i) + { + x = 1 * 2 * 3; + } + std::cout << "Finish Loop 2" << std::endl; + //sw.clear(); + //csw.clear(); + sw.start(); + csw.start(); + + for (int i = 0; i < 1000000000; ++i) + { + x = 1 * 2 * 3; + } + std::cout << "Finish Loop 3" << std::endl; + std::cout << "clock(): " << clock() / CLOCKS_PER_SEC << std::endl; + std::cout << "time(): " << time(NULL) << std::endl; + std::cout << "RTStop: " << std::setprecision(50) << sw.stop() + << std::endl; + std::cout << "CStop: " << std::setprecision(50) << csw.stop() + << std::endl; + + } + catch (except::Throwable& t) + { + std::cerr << "Caught throwable: " << t.toString() << std::endl; + exit( EXIT_FAILURE); + } + catch (...) + { + std::cerr << "Caught unnamed exception" << std::endl; + } + return 0; +} diff --git a/modules/c++/sys/tests/DirectoryTest.cpp b/modules/c++/sys/tests/DirectoryTest.cpp new file mode 100644 index 000000000..cfbfab396 --- /dev/null +++ b/modules/c++/sys/tests/DirectoryTest.cpp @@ -0,0 +1,66 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include +#include +#include + +int main(int argc, char **argv) +{ + try + { + + sys::TimeStamp ts; + std::cout << ts.gmt() << std::endl; + std::cout << ts.local() << std::endl; + + sys::OS os; + std::cout << os["PATH"] << std::endl; + + std::string cwd = os.getCurrentWorkingDirectory(); + + sys::Path path(cwd); + + std::cout << "Searching directory: " << path << std::endl; + + sys::DirectoryEntry d(path); + + for (sys::DirectoryEntry::Iterator p = d.begin(); p != d.end(); ++p) + { + std::cout << "Found file: " << *p << std::endl; + } + } + catch (except::Throwable& t) + { + std::cout << t.toString() << std::endl; + } + catch (std::exception& ex) + { + std::cout << ex.what() << std::endl; + } + catch (...) + { + std::cout << "Caught unnknown throwable" << std::endl; + } + return 0; + +} diff --git a/modules/c++/sys/tests/ErrTest.cpp b/modules/c++/sys/tests/ErrTest.cpp new file mode 100644 index 000000000..a0531f995 --- /dev/null +++ b/modules/c++/sys/tests/ErrTest.cpp @@ -0,0 +1,50 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include +#include +#include + +int main(int argc, char** argv) +{ + try + { + // open non-existant file + FILE* f = fopen("supercalifragilisticexpialidocious.tmpl", "r"); + + if (!f) throw except::Exception(Ctxt("File not Found! That's weird!?")); + } + catch (...) + { + sys::Err err; + sys::Err copyErr (err); + sys::Err assignErr = err; + + std::cout << "Default Constructed Error : " << err.toString() << std::endl; + std::cout << "Copy Constructed Error : " << copyErr.toString() << std::endl; + std::cout << "Assignment Constructed Error : " << assignErr.toString() << std::endl; + + sys::SocketErr socErr; + std::cout << "Default Constructed Socket Error : " << socErr.toString() << std::endl; + } +} + diff --git a/modules/c++/sys/tests/ExecTest.cpp b/modules/c++/sys/tests/ExecTest.cpp new file mode 100644 index 000000000..af63936a1 --- /dev/null +++ b/modules/c++/sys/tests/ExecTest.cpp @@ -0,0 +1,60 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include +#include +#include +#include "sys/StopWatch.h" + +using namespace sys; + +int main(int argc, char **argv) +{ + try + { + std::string cmd; + + if (argc > 1) + cmd = std::string(argv[1]); + else + cmd = "echo Scream!"; + + sys::Exec exe(cmd); + exe.run(); + } + catch (const except::Throwable& ex) + { + std::cerr << "Caught C++ exception" << + ex.getMessage() << std::endl; + } + catch (const std::exception& ex) + { + std::cerr << "Caught standard exception" << + ex.what() << std::endl; + } + catch (...) + { + std::cerr << "Caught unnamed Unwanted exception" << std::endl; + } + return 0; +} + diff --git a/modules/c++/sys/tests/MMapReadOnlyTest.cpp b/modules/c++/sys/tests/MMapReadOnlyTest.cpp new file mode 100644 index 000000000..221e18ef4 --- /dev/null +++ b/modules/c++/sys/tests/MMapReadOnlyTest.cpp @@ -0,0 +1,58 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include +#include + +int main(int argc, char** argv) +{ + + if (argc != 2) + die_printf("Usage: %s \n", argv[0]); + + try + { + std::string fname = argv[1]; + sys::OS os; + + sys::Handle_T handle; + size_t size = os.getSize(fname); + FILE* file = fopen(fname.c_str(), "r+b"); + handle = fileno(file); + + char* memLoc = (char*) os.mapFile(handle, size, PROT_READ, MAP_SHARED, + 0); + + for (int i = 0; i < size; i++) + std::cout << memLoc[i]; + + os.unmapFile(memLoc, size); + + fclose(file); + return 0; + } + catch (except::Throwable& t) + { + std::cout << t.toString() << std::endl; + } + +} diff --git a/modules/c++/sys/tests/MutexTest.cpp b/modules/c++/sys/tests/MutexTest.cpp new file mode 100644 index 000000000..1978c597a --- /dev/null +++ b/modules/c++/sys/tests/MutexTest.cpp @@ -0,0 +1,83 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#include +#include +#include "sys/Thread.h" +#include "sys/Mutex.h" + + +#if defined(_REENTRANT) + +using namespace sys; +const int MAX_THREADS = 9; +const int THREAD_LOOPS = 3; + +Mutex mutexCout; + +std::string itos (int arg) { + std::ostringstream buffer; + buffer << arg; + return buffer.str(); +} + +class DemoThread : public Thread +{ +protected: + void run() { + for (int i = 0 ; i < THREAD_LOOPS ; i++ ) { + mutexCout.lock(); + std::cout << getName() + " is running" << std::endl; + mutexCout.unlock(); + sleep(1); + } + mutexCout.lock(); + std::cout << getName() + " is finished" << std::endl; + mutexCout.unlock(); + } + +public: + DemoThread(std::string name) : Thread(name) {}; +}; + + +int main (int argc, char* argv[]) +{ + DemoThread *threads[MAX_THREADS]; + for (int i = 0 ; i < MAX_THREADS ; i++ ) { + threads[i] = new DemoThread( "Thread " + itos(i+1) ); + threads[i]->start(); + } + for (int j = 0; j < MAX_THREADS; j++ ) { + threads[j]->join(); + } +} +#else +int main() +{ + std::cout << "Sorry, your implementation of sys is not thread-enabled" << std::endl; + return 0; +} +#endif + + diff --git a/modules/c++/sys/tests/OSTest.cpp b/modules/c++/sys/tests/OSTest.cpp new file mode 100644 index 000000000..c6fff6d10 --- /dev/null +++ b/modules/c++/sys/tests/OSTest.cpp @@ -0,0 +1,152 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include +#include +#include +#include "sys/StopWatch.h" + +using namespace sys; + +int main(int argc, char **argv) +{ + try + { + sys::OS os; + + std::string fileToFind = os.getCurrentWorkingDirectory() + + os.getDelimiter() + "blah.txt"; + + // Some System info + std::cout << "Some System Info" << std::endl; + std::cout << "==============================================" + << std::endl; + std::cout << "Host: " << os.getNodeName() << std::endl; + std::cout << "User path: " << os["PATH"] << std::endl; + std::cout << "Platform: " << os.getPlatformName() << std::endl; + std::cout << "Num CPUs: " << os.getNumCPUs() << std::endl; + std::cout << "The delimiter on this platform: " << os.getDelimiter() + << std::endl; + std::cout << "The process id: " << os.getProcessId() << std::endl; + //std::cout << "The user is: " << os.getUsername() << std::endl; + ///////////////////////////////////////////// + // File exists check!!! + if (argc == 2) + { + std::cerr << "I will look for " << argv[1] << std::endl; + fileToFind = argv[1]; + } + + if (os.exists(fileToFind)) + { + std::cout << "Found file: " << fileToFind << std::endl; + std::cout << "File is of size: " << os.getSize(fileToFind) + << std::endl; + } + else + { + std::cerr << "Did not find file: " << fileToFind << std::endl; + } + ////////////////////////////////////////////////// + // Test directory functions + std::string cwd = os.getCurrentWorkingDirectory(); + if (os.isFile(cwd)) + { + std::cerr << "Shouldnt be here: " << cwd << " is not a file!!" + << std::endl; + } + else if (os.isDirectory(cwd)) + { + std::cout << "Found directory: " << cwd << std::endl; + } + /////////////////////////////////////////////////// + // Test temp file stuff + std::string tempFileName = os.getTempName(); + std::ofstream ofs(tempFileName.c_str()); + if (!ofs.is_open()) + throw except::Exception(FmtX("Could not open file named: %s", + tempFileName.c_str())); + ofs << "Im writing some crap to this file!" << std::endl; + ofs.close(); + std::cout << "Created file: " << tempFileName << " with size: " + << os.getSize(tempFileName) << std::endl; + os.remove(tempFileName); + std::cout << "Killed file: " << tempFileName << std::endl; + + if (!os.makeDirectory("TEST_DIRECTORY")) + std::cout << "failed to create test directory" << std::endl; + + else + { + std::cout << "Created test directory: TEST_DIRECTORY" << std::endl; + } + if (!os.remove("TEST_DIRECTORY")) + { + std::cout << "test directory removal failed:" + << sys::Err().toString() << std::endl; + } + else + { + std::cout << "Killed test directory" << std::endl; + } + + std::cout << "Time Now: " << time(NULL) << std::endl; + sys::RealTimeStopWatch sw; + //std::cout << "CPS: " << CLOCKS_PER_SEC << std::endl; + // std::cout << "Clock: " << clock() << std::endl; + std::cout << "Start: " << sw.start() << std::endl; + int x = 0; + for (int i = 0; i < 1000000000; ++i) + { + x = 1 * 2 * 3; + } + std::cout << "Finish Loop 1" << std::endl; + sw.pause(); + for (int i = 0; i < 1000000000; ++i) + { + x = 1 * 2 * 3; + } + std::cout << "Finish Loop 2" << std::endl; + //sw.start(); + //sw.clear(); + for (int i = 0; i < 1000000000; ++i) + { + x = 1 * 2 * 3; + } + std::cout << "Finish Loop 3" << std::endl; + std::cout << "Stop: " << std::setprecision(50) << sw.stop() + << std::endl; + std::cout << "Time Now: " << time(NULL) << std::endl; + // std::cout << "Clock: " << clock() << std::endl; + + } + catch (except::Throwable& t) + { + std::cerr << "Caught throwable: " << t.toString() << std::endl; + exit( EXIT_FAILURE); + } + catch (...) + { + std::cerr << "Caught unnamed exception" << std::endl; + } + return 0; +} diff --git a/modules/c++/sys/tests/PathTest.cpp b/modules/c++/sys/tests/PathTest.cpp new file mode 100644 index 000000000..3845353d6 --- /dev/null +++ b/modules/c++/sys/tests/PathTest.cpp @@ -0,0 +1,149 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include +#include +#include + +using namespace sys; + +int main(int argc, char **argv) +{ + try + { + sys::OS os; + std::string fileName = os.getCurrentWorkingDirectory() + + os.getDelimiter() + ".." + os.getDelimiter() + "blah.txt"; + + std::cout << "File Name as string: " << fileName << std::endl; + + Path parentPath(os.getCurrentWorkingDirectory(), ".."); + Path filePath(parentPath, "blah.txt"); + std::cout << "File Name as path: " << filePath.getPath() << std::endl; + + Path::StringPair parts = Path::splitPath(fileName); + std::cout << "1) " << parts.first << " --- " << parts.second + << std::endl; + + parts = filePath.split(); + std::cout << "2) " << parts.first << " --- " << parts.second + << std::endl; + parts = Path::splitDrive("c:/junk.txt"); + std::cout << "1) " << parts.first << " --- " << parts.second + << std::endl; + filePath = Path("c:/junk.txt"); + parts = filePath.splitDrive(); + std::cout << "2) " << parts.first << " --- " << parts.second + << std::endl; + filePath = Path("/data/nitf///data/vendor1.ntf"); + + std::string base = + Path::basename("/data/nitf///data/vendor1.ntf", true); + std::cout << "1) " << base << std::endl; + + base = filePath.getBasePath(true); + std::cout << "2) " << base << std::endl; + + parts = Path::splitPath("/data.txt"); + std::cout << parts.first << " --- " << parts.second << std::endl; + + parts = Path::splitExt(fileName); + std::cout << parts.first << " --- " << parts.second << std::endl; + + parts = Path::splitExt(Path::splitPath(fileName).second); + std::cout << parts.first << " --- " << parts.second << std::endl; + + std::cout << Path::normalizePath(fileName) << std::endl; + std::cout << Path::normalizePath("c:/data/nitf/data/vendor1.ntf") + << std::endl; + std::cout << Path("/data/nitf///data/vendor1.ntf").normalize() + << std::endl; + + std::cout << Path::normalizePath("/data/nitf///data/../vendor1.ntf") + << std::endl; + + std::cout + << Path::normalizePath( + "../data/../../..//./nitf///data/../vendor1.ntf") + << std::endl; + + std::cout + << Path::normalizePath( + "data/junk/tzellman/../../../../../..///./nitf///data/../vendor1.ntf") + << std::endl; + + std::cout << "1) " << Path("/data/junk/", "test.txt").getPath() + << std::endl; + std::cout << "2) " << Path::joinPaths("/data/junk/", "///test.txt") + << std::endl; + std::cout << "3) " << Path("/data/junk/").join("/test.txt").getPath() + << std::endl; + std::cout << "4) " << Path::joinPaths("/data/junk", "test.txt") + << std::endl; + std::cout + << Path( + "data/junk/tzellman/../../../../../..///./nitf///data/../vendor1.ntf").getAbsolutePath() + << std::endl; + std::cout + << Path::normalizePath( + "data/junk/tzellman/../../../../../..///./nitf///data/../vendor1.ntf") + << std::endl; + std::cout + << Path::absolutePath( + "c:/data/junk/tzellman/../../../../../..///./nitf///data/../vendor1.ntf") + << std::endl; + std::cout << Path::normalizePath("c:/../../../junk.txt") << std::endl; + + std::cout << Path::absolutePath("/home/tzellman/dev/") << std::endl; + + const std::string currentDirWithDelimiter = + os.getCurrentWorkingDirectory() + os.getDelimiter(); + parts = Path::splitPath(currentDirWithDelimiter); + std::cout << "1) " << parts.first << " --- " << parts.second + << std::endl; + + std::cout << Path::normalizePath(currentDirWithDelimiter) + << std::endl; + + std::cout << Path::absolutePath(currentDirWithDelimiter) + << std::endl; + + std::cout << Path::joinPaths(parts.first + os.getDelimiter(), + parts.second + os.getDelimiter()) + << std::endl; + } + catch (const except::Throwable& t) + { + std::cerr << "Caught throwable: " << t.toString() << std::endl; + exit(EXIT_FAILURE); + } + catch (const std::exception& ex) + { + std::cerr << "Caught std::exception: " << ex.what() << std::endl; + exit(EXIT_FAILURE); + } + catch (...) + { + std::cerr << "Caught unnamed exception" << std::endl; + } + return 0; +} diff --git a/modules/c++/sys/tests/ProcessTest1.cpp b/modules/c++/sys/tests/ProcessTest1.cpp new file mode 100644 index 000000000..655c6106f --- /dev/null +++ b/modules/c++/sys/tests/ProcessTest1.cpp @@ -0,0 +1,82 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#include +#include +using namespace sys; +using namespace except; + +#include +#include +using namespace std; + +class LazyChild : public Process +{ +public: + LazyChild() {} + ~LazyChild() {} + void run() + { + cout << "In Child" << endl; + OS os; + os.millisleep(1000); + } +}; + +class ListChild : public Process +{ +public: + ListChild(char **argv) : mArgv(argv) {} + ~ListChild() {} + void run() + { + cout << "In Child with argv:" << mArgv[0] << endl; + execv("/usr/bin/ls", mArgv); + } + char **mArgv; +}; + +int main(int argc, char**argv) +{ + ListChild process1(argv); + process1.start(); + process1.waitFor(); + + ListChild process2(argv); + process2.start(); + process2.waitFor(); + + ListChild process3(argv); + process3.start(); + process3.waitFor(); + + ListChild process4(argv); + process4.start(); + process4.waitFor(); + + LazyChild lc; + lc.start(); + lc.waitFor(); + + return 0; +} diff --git a/modules/c++/sys/tests/RaiseTest.cpp b/modules/c++/sys/tests/RaiseTest.cpp new file mode 100644 index 000000000..617541303 --- /dev/null +++ b/modules/c++/sys/tests/RaiseTest.cpp @@ -0,0 +1,122 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include +#include +#include +#include +using namespace except; +using namespace sys; +using namespace std; + +class NotAddableError : public Error +{ +public: + NotAddableError(int size) + { + std::ostringstream m; + m << "Not addable because size is < 2: " << size; + mMessage = m.str(); + } +}; + +class GreaterThan10Ex : public Exception +{ +public: + GreaterThan10Ex(int size) + { + std::ostringstream m; + m << "Not addable because value is > 10: " << size; + mMessage = m.str(); + } +}; +class NegativeNumberEx : public Exception +{ +public: + + NegativeNumberEx(int size) + { + std::ostringstream m; + m << "Not addable because value is < 0: " << size; + mMessage = m.str(); + } +}; + +int main(int argc, char **argv) +{ + try + { + vectorv; + for (int i = 1; i < argc; i++) + { + v.push_back(atoi(argv[i])); + } + if (v.size() < 2) + { + + NotAddableError nae(v.size()); + throw(nae); + } + int acc = 0; + for (size_t i = 0; i < v.size(); i++) + { + acc += v[i]; + } + + if (acc < 0) + { + + NegativeNumberEx nne(acc); + throw(nne); + + } + else if (acc > 10) + { + GreaterThan10Ex gt10(acc); + throw(gt10); + } + else + { + //__status__("Succeeded"); + } + } + catch (Exception& ex) + { + cout << "Ex: " << ex.toString() << endl; + } + catch (Error& err) + { + cout << "Err: " << err.toString() << endl; + } + catch (Throwable& t) + { + cout << "Throwable: " << t.toString() << endl; + } + + catch (...) + { + cout << "No clue what kind of exception" << endl; + } + + return 0; + +} diff --git a/modules/c++/sys/tests/ReadWriteMutexTest.cpp b/modules/c++/sys/tests/ReadWriteMutexTest.cpp new file mode 100644 index 000000000..81e24a913 --- /dev/null +++ b/modules/c++/sys/tests/ReadWriteMutexTest.cpp @@ -0,0 +1,100 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#if defined(__APPLE_CC__) +#include +int main (int argc, char *argv[]) +{ + std::cout << "Sorry no semaphores" << std::endl; + return 0; +} + +#else + +#include +#include +#include "sys/Thread.h" +#include "sys/ReadWriteMutex.h" + +using namespace sys; +const int MAX_THREADS = 10; + +ReadWriteMutex rwLock(10); +Mutex mutexCout; + +std::string itos(int arg) +{ + std::ostringstream os; + os << arg; + return os.str(); +} + +std::string BUFFER[1]; + +class ReadWriteThread : public Thread +{ +protected: + void run() { + + for(int i=0; i < 5; ++i) + { + rwLock.lockWrite(); + BUFFER[0] = getName().substr(7); + mutexCout.lock(); + std::cout << getName() << " write " << BUFFER[0] << std::endl; + mutexCout.unlock(); + sleep(1); + rwLock.unlockWrite(); + } + + + rwLock.lockRead(); + std::string b = BUFFER[0]; + for(int i=0; i < 5; ++i) + { + assert(b == BUFFER[0]); + b = BUFFER[0]; + mutexCout.lock(); + std::cout << getName() << " read " << b << std::endl; + mutexCout.unlock(); + sleep(1); + } + rwLock.unlockRead(); + } + +public: + ReadWriteThread(std::string name) : Thread(name) {}; +}; + +int main (int argc, char* argv[]) +{ + Thread *threads[MAX_THREADS]; + for (int i = 0 ; i < MAX_THREADS ; i++ ) { + threads[i] = new ReadWriteThread( "Thread " + itos(i) ); + threads[i]->start(); + } + for (int j = 0; j < MAX_THREADS; j++ ) { + threads[j]->join(); + } +} +#endif diff --git a/modules/c++/sys/tests/ReentrantTest.cpp b/modules/c++/sys/tests/ReentrantTest.cpp new file mode 100644 index 000000000..6a4bd5a24 --- /dev/null +++ b/modules/c++/sys/tests/ReentrantTest.cpp @@ -0,0 +1,76 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include +#include +using namespace sys; + +#if defined(_REENTRANT) +class NoteThread : public Thread +{ +public: + NoteThread() + { std::cout << "Constructed a thread" << std::endl;} + void run() + { std::cout << "Running a thread" << std::endl;} + + ~NoteThread() + { std::cout << "Completed a thread. Destroying..." << std::endl;} + +}; +#endif +int main() +{ +#if defined(_REENTRANT) + try + { + std::cout << "Your implementation of sys is multi-threaded" << std::endl; + NoteThread* nThr = new NoteThread; + std::cout << "Your thread type is: " << nThr->getNativeType() << std::endl; + + nThr->start(); + nThr->join(); + delete nThr; + std::cout << "Exiting" << std::endl; + } + + catch (except::Throwable& t) + { + std::cout << "Caught throwable: " << t.toString() << std::endl; + + } + catch (std::exception& e) + { + std::cout << "Caught stl exception: " << e.what() << std::endl; + } + catch (...) + { + std::cout << "Caught unknown exception" << std::endl; + } +#else + + std::cout << "Your implementation of sys is single-threaded" << std::endl; +#endif + return 0; + +} + diff --git a/modules/c++/sys/tests/ThreadFreeTest.cpp b/modules/c++/sys/tests/ThreadFreeTest.cpp new file mode 100644 index 000000000..3287b4621 --- /dev/null +++ b/modules/c++/sys/tests/ThreadFreeTest.cpp @@ -0,0 +1,94 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include +#include +using namespace sys; +using namespace std; + +class MyRunTask : public Runnable +{ +public: + int result; + + MyRunTask() + { + result = 0; + } + virtual ~MyRunTask() + { + } + + virtual void run() + { + result = 1; + } +}; + +int main(int argc, char *argv[]) +{ + Thread *thread; + MyRunTask *task1; + MyRunTask *task2; + MyRunTask *task3; + + try + { + task1 = new MyRunTask(); + thread = new Thread(task1); + thread->start(); + thread->join(); + task2 = new MyRunTask(); + + if (task1->result != 1) + { + cout << "Task1 not run, result: " << task1->result << endl; + return -1; + } + + delete thread; + + task3 = new MyRunTask(); + + if (task1 == task3) + cout << "Task1 freed" << endl; + + + delete task2; + delete task3; + + std::cout << "Finished all" << std::endl; + } + + catch (except::Throwable& t) + { + cout << "Exception Caught: " << t.toString() << endl; + return -1; + } + catch (...) + { + cout << "Exception Caught!" << endl; + return -1; + } + + return 0; +} diff --git a/modules/c++/sys/tests/ThreadTest4.cpp b/modules/c++/sys/tests/ThreadTest4.cpp new file mode 100644 index 000000000..e6266b313 --- /dev/null +++ b/modules/c++/sys/tests/ThreadTest4.cpp @@ -0,0 +1,153 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include + +#if defined(_REENTRANT) + +using namespace sys; +using namespace std; + +class Getter : public sys::Runnable +{ +public: + Getter(sys::Mutex *by, int * val, int n) : theVal(val), syncBy(by), id(n) + {} + virtual ~Getter() + {} + + virtual void run() + { + for (int i = 0; i < 250; i++) + { + + std::cout << "Getter::run: " << std::endl; + std::cout << typeid(this).name() << std::endl; + syncBy->lock(); + int x = get(); + cout << "Thread id: "<< id << " got back " << x << endl; + syncBy->unlock(); + sys::Thread::yield(); + } + } + int get() + { + + return *theVal; + } +protected: + int *theVal; + sys::Mutex *syncBy; + int id; + +}; +class Putter : public sys::Runnable +{ +public: + Putter(sys::Mutex *by,int *val, int n) : theVal(val), syncBy(by), id(n) + {} + virtual ~Putter() + {} + + virtual void run() + { + + std::cout << "Putter::run: " << std::endl; + std::cout << typeid(this).name() << std::endl; + + for (int i = 0; i < 250; i++) + { + syncBy->lock(); + set(i); + cout << "Thread id: "<< id << " set to " << i << endl; + syncBy->unlock(); + + sys::Thread::yield(); + + } + + } + void set(int val) + { + *theVal = val; + } +protected: + int *theVal; + sys::Mutex *syncBy; + int id; +}; + +int main() +{ + try + { + int val = 24; + sys::Mutex syncBy; + sys::Thread *gT[5]; + sys::Thread *pT[5]; + + for (int i = 0; i < 5; i++) + { + + gT[i] = new sys::Thread(new Getter(&syncBy, &val, i)); + gT[i]->start(); + + pT[i] = new sys::Thread(new Putter(&syncBy, &val, i)); + pT[i]->start(); + + // //printf("p (&) %x\n", p); + // sys::Thread(p).start(); + // sys::Thread(new Putter(&syncBy, &val, i)).start(); + } + + for (int i = 0; i < 5; i++) + { + gT[i]->join(); + cout << "Joined on gT[" << i << "]" << endl; + delete gT[i]; + pT[i]->join(); + delete pT[i]; + cout << "Joined on pT[" << i << "]" << endl; + } + // sys::Thread::yield(); + + } + catch (except::Exception& e) + { + cout << "Caught Exception: " << e.toString() << endl; + } + catch (...) + { + cout << "Unknown exception" << endl; + } + return 0; +}; + +#else + +int main() +{ + std::cout << "sys is not Multithreaded" << std::endl; + return 0; +} + +#endif diff --git a/modules/c++/sys/tests/ThreadTest5.cpp b/modules/c++/sys/tests/ThreadTest5.cpp new file mode 100644 index 000000000..5149eaac6 --- /dev/null +++ b/modules/c++/sys/tests/ThreadTest5.cpp @@ -0,0 +1,98 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include +using namespace sys; +using namespace std; + +#if defined(_REENTRANT) + +class TestThread : public Thread +{ +public: + TestThread(int *val) + { + + mVal = val; + std::cout << "Constructing thread with value " << *mVal << std::endl; + } + ~TestThread() + { + std::cout << "Destructing thread with value " << *mVal << std::endl; + delete mVal; + } + + void run() + { + cout << "mVal: " << *mVal << endl; + } + int *mVal; +}; + +int main() +{ + std::vector< TestThread *> tAry; + tAry.resize(5); + + try + { + for (int i = 0; i < 5; i++) + { + tAry[i] = new TestThread(new int(i + 1)); + tAry[i]->start(); + } + // TestThread(new int(1)).start(); + // TestThread(new int(2)).start(); + // TestThread(new int(3)).start(); + // TestThread(new int(4)).start(); + // TestThread(new int(5)).start(); + + for (int i = 0; i < 5; i++) + { + tAry[i]->join(); + } + while (tAry.size()) + { + TestThread *t = tAry.back(); + tAry.pop_back(); + delete t; + } + + } + catch (except::Exception& e) + { + cout << e.toString() << endl; + } + catch (...) + { + cout << "Unknown exception" << endl; + } + return 0; +}; +#else +int main() +{ + std::cout << "sys is not Multithreaded" << std::endl; + return 0; +} + +#endif diff --git a/modules/c++/sys/unittests/test_atomic_counter.cpp b/modules/c++/sys/unittests/test_atomic_counter.cpp new file mode 100644 index 000000000..aae99a62c --- /dev/null +++ b/modules/c++/sys/unittests/test_atomic_counter.cpp @@ -0,0 +1,255 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include +#include +#include + +#include +#include +#include + +#include "TestCase.h" + +namespace +{ +typedef sys::AtomicCounter::ValueType ValueType; + +TEST_CASE(testConstructor) +{ + TEST_ASSERT_EQ(sys::AtomicCounter().get(), 0); + TEST_ASSERT_EQ(sys::AtomicCounter(12345).get(), 12345); + + TEST_ASSERT_EQ( + sys::AtomicCounter(std::numeric_limits::max()).get(), + std::numeric_limits::max()); +} + +TEST_CASE(testIncrement) +{ + sys::AtomicCounter ctr(100); + + TEST_ASSERT_EQ(ctr.getThenIncrement(), 100); + TEST_ASSERT_EQ(ctr.get(), 101); + + TEST_ASSERT_EQ(ctr.getThenIncrement(), 101); + TEST_ASSERT_EQ(ctr.get(), 102); + + ValueType value(ctr++); + TEST_ASSERT_EQ(value, 102); + TEST_ASSERT_EQ(ctr.get(), 103); + + TEST_ASSERT_EQ(ctr.incrementThenGet(), 104); + TEST_ASSERT_EQ(ctr.get(), 104); + + value = ++ctr; + TEST_ASSERT_EQ(value, 105); + TEST_ASSERT_EQ(ctr.get(), 105); +} + +TEST_CASE(testDecrement) +{ + sys::AtomicCounter ctr(100); + + TEST_ASSERT_EQ(ctr.getThenDecrement(), 100); + TEST_ASSERT_EQ(ctr.get(), 99); + + TEST_ASSERT_EQ(ctr.getThenDecrement(), 99); + TEST_ASSERT_EQ(ctr.get(), 98); + + ValueType value(ctr--); + TEST_ASSERT_EQ(value, 98); + TEST_ASSERT_EQ(ctr.get(), 97); + + TEST_ASSERT_EQ(ctr.decrementThenGet(), 96); + TEST_ASSERT_EQ(ctr.get(), 96); + + value = --ctr; + TEST_ASSERT_EQ(value, 95); + TEST_ASSERT_EQ(ctr.get(), 95); +} + +class IncrementAtomicCounter : public sys::Runnable +{ +public: + IncrementAtomicCounter(size_t numIncrements, + sys::AtomicCounter& ctr, + ValueType* values) : + mNumIncrements(numIncrements), + mCtr(ctr), + mValues(values) + { + } + + virtual void run() + { + for (size_t ii = 0; ii < mNumIncrements; ++ii) + { + mValues[ii] = mCtr.getThenIncrement(); + } + } + +private: + const size_t mNumIncrements; + sys::AtomicCounter& mCtr; + ValueType* const mValues; +}; + +TEST_CASE(testThreadedIncrement) +{ + const size_t numThreads = 13; + const size_t numIncrements = 1000; + + std::vector values(numThreads * numIncrements); + std::vector valuesPtr(numThreads); + std::vector threads(numThreads); + sys::AtomicCounter ctr(0); + + // Create all the threads + ValueType* ptr(&values[0]); + for (size_t ii = 0; ii < numThreads; ++ii, ptr += numIncrements) + { + threads[ii] = + new sys::Thread(new IncrementAtomicCounter(numIncrements, + ctr, + ptr)); + valuesPtr[ii] = ptr; + } + + for (size_t ii = 0; ii < numThreads; ++ii) + { + threads[ii]->start(); + } + + // Wait for them all + for (size_t ii = 0; ii < numThreads; ++ii) + { + threads[ii]->join(); + delete threads[ii]; + } + + // Each thread should have its values monotonically increasing + for (size_t ii = 0; ii < numThreads; ++ii) + { + const ValueType* const threadValues(valuesPtr[ii]); + for (size_t jj = 0, end = numIncrements - 1; jj < end; ++jj) + { + TEST_ASSERT(threadValues[jj + 1] > threadValues[jj]); + } + } + + // We should have gotten every value along the way + std::sort(values.begin(), values.end()); + for (size_t ii = 0; ii < values.size(); ++ii) + { + TEST_ASSERT_EQ(values[ii], (sys::SSize_T)ii); + } +} + +class DecrementAtomicCounter : public sys::Runnable +{ +public: + DecrementAtomicCounter(size_t numDecrements, + sys::AtomicCounter& ctr, + ValueType* values) : + mNumDecrements(numDecrements), + mCtr(ctr), + mValues(values) + { + } + + virtual void run() + { + for (size_t ii = 0; ii < mNumDecrements; ++ii) + { + mValues[ii] = mCtr.getThenDecrement(); + } + } + +private: + const size_t mNumDecrements; + sys::AtomicCounter& mCtr; + ValueType* const mValues; +}; + +TEST_CASE(testThreadedDecrement) +{ + const size_t numThreads = 13; + const size_t numDecrements = 1000; + + std::vector values(numThreads * numDecrements); + std::vector valuesPtr(numThreads); + std::vector threads(numThreads); + sys::AtomicCounter ctr(numThreads * numDecrements - 1); + + // Create all the threads + ValueType* ptr(&values[0]); + for (size_t ii = 0; ii < numThreads; ++ii, ptr += numDecrements) + { + threads[ii] = + new sys::Thread(new DecrementAtomicCounter(numDecrements, + ctr, + ptr)); + valuesPtr[ii] = ptr; + } + + for (size_t ii = 0; ii < numThreads; ++ii) + { + threads[ii]->start(); + } + + // Wait for them all + for (size_t ii = 0; ii < numThreads; ++ii) + { + threads[ii]->join(); + delete threads[ii]; + } + + // Each thread should have its values monotonically decreasing + for (size_t ii = 0; ii < numThreads; ++ii) + { + const ValueType* const threadValues(valuesPtr[ii]); + for (size_t jj = 0, end = numDecrements - 1; jj < end; ++jj) + { + TEST_ASSERT(threadValues[jj + 1] < threadValues[jj]); + } + } + + // We should have gotten every value along the way + std::sort(values.begin(), values.end()); + for (size_t ii = 0; ii < values.size(); ++ii) + { + TEST_ASSERT_EQ(values[ii], (sys::SSize_T)ii); + } +} +} + +int main(int argc, char** argv) +{ + TEST_CHECK(testConstructor); + TEST_CHECK(testIncrement); + TEST_CHECK(testDecrement); + TEST_CHECK(testThreadedIncrement); + TEST_CHECK(testThreadedDecrement); + + return 0; +} diff --git a/modules/c++/sys/unittests/test_conditionvar.cpp b/modules/c++/sys/unittests/test_conditionvar.cpp new file mode 100644 index 000000000..7a826560b --- /dev/null +++ b/modules/c++/sys/unittests/test_conditionvar.cpp @@ -0,0 +1,56 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2012, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include + +#include "TestCase.h" + +namespace +{ + +TEST_CASE(testDefaultConstructor) +{ + sys::ConditionVar cond; + + cond.acquireLock(); + cond.dropLock(); +} + +TEST_CASE(testParameterizedConstructor) +{ + sys::Mutex mutex; + sys::ConditionVar cond(&mutex, false); + + cond.acquireLock(); + cond.dropLock(); +} + +} + +int main(int argc, char* argv[]) +{ + TEST_CHECK(testDefaultConstructor); + TEST_CHECK(testParameterizedConstructor); + + return 0; +} + diff --git a/modules/c++/sys/unittests/test_datetime.cpp b/modules/c++/sys/unittests/test_datetime.cpp new file mode 100755 index 000000000..88132c5e6 --- /dev/null +++ b/modules/c++/sys/unittests/test_datetime.cpp @@ -0,0 +1,149 @@ +/* ========================================================================= + * This file is part of sys-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2012, General Dynamics - Advanced Information Systems + * + * sys-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include +#include +#include + +#include "TestCase.h" + +namespace +{ + +TEST_CASE(testDefaultConstructor) +{ + sys::OS os; + + sys::LocalDateTime l1; + sys::UTCDateTime u1; + + os.millisleep(100); + + sys::LocalDateTime l2; + sys::UTCDateTime u2; + + TEST_ASSERT(l1.getMonth() >= 1 && l1.getMonth() <= 12); + TEST_ASSERT(l1.getDayOfMonth() >= 1 && l1.getDayOfMonth() <= 31); + TEST_ASSERT(l1.getDayOfWeek() >= 1 && l1.getDayOfWeek() <= 7); + TEST_ASSERT(l1.getDayOfYear() >= 1 && l1.getDayOfYear() <= 366); + TEST_ASSERT(l1.getHour() >= 0 && l1.getHour() <= 23); + TEST_ASSERT(l1.getMinute() >= 0 && l1.getMinute() <= 59); + TEST_ASSERT(l1.getSecond() >= 0 && l1.getSecond() <= 59); + + TEST_ASSERT(u1.getMonth() >= 1 && u1.getMonth() <= 12); + TEST_ASSERT(u1.getDayOfMonth() >= 1 && u1.getDayOfMonth() <= 31); + TEST_ASSERT(u1.getDayOfWeek() >= 1 && u1.getDayOfWeek() <= 7); + TEST_ASSERT(u1.getDayOfYear() >= 1 && u1.getDayOfYear() <= 366); + TEST_ASSERT(u1.getHour() >= 0 && u1.getHour() <= 23); + TEST_ASSERT(u1.getMinute() >= 0 && u1.getMinute() <= 59); + TEST_ASSERT(u1.getSecond() >= 0 && u1.getSecond() <= 59); + + TEST_ASSERT(l2.getMonth() >= 1 && l2.getMonth() <= 12); + TEST_ASSERT(l2.getDayOfMonth() >= 1 && l2.getDayOfMonth() <= 31); + TEST_ASSERT(l2.getDayOfWeek() >= 1 && l2.getDayOfWeek() <= 7); + TEST_ASSERT(l2.getDayOfYear() >= 1 && l2.getDayOfYear() <= 366); + TEST_ASSERT(l2.getHour() >= 0 && l2.getHour() <= 23); + TEST_ASSERT(l2.getMinute() >= 0 && l2.getMinute() <= 59); + TEST_ASSERT(l2.getSecond() >= 0 && l2.getSecond() <= 59); + + TEST_ASSERT(u2.getMonth() >= 1 && u2.getMonth() <= 12); + TEST_ASSERT(u2.getDayOfMonth() >= 1 && u2.getDayOfMonth() <= 31); + TEST_ASSERT(u2.getDayOfWeek() >= 1 && u2.getDayOfWeek() <= 7); + TEST_ASSERT(u2.getDayOfYear() >= 1 && u2.getDayOfYear() <= 366); + TEST_ASSERT(u2.getHour() >= 0 && u2.getHour() <= 23); + TEST_ASSERT(u2.getMinute() >= 0 && u2.getMinute() <= 59); + TEST_ASSERT(u2.getSecond() >= 0 && u2.getSecond() <= 59); + + TEST_ASSERT(l1 == l1); + TEST_ASSERT(l1 != l2); + TEST_ASSERT(l1 < l2); + TEST_ASSERT(l2 > l1); +} + +TEST_CASE(testParameterizedConstructor) +{ + sys::UTCDateTime u1(0); + + TEST_ASSERT_EQ(u1.getYear(), 1970); + TEST_ASSERT_EQ(u1.getMonth(), 1); + TEST_ASSERT_EQ(u1.getHour(), 0); + TEST_ASSERT_EQ(u1.getMinute(), 0); + TEST_ASSERT_EQ(u1.getSecond(), 0); + TEST_ASSERT_EQ(u1.getTimeInMillis(), 0); + + // test H:M:S constructor + sys::LocalDateTime l2(10, 2, 42.24); + TEST_ASSERT_EQ(l2.getHour(), 10); + TEST_ASSERT_EQ(l2.getMinute(), 2); + TEST_ASSERT_EQ(l2.getSecond(), 42.24); + + // test H:M:S constructor + sys::UTCDateTime u2(10, 2, 42.24); + TEST_ASSERT_EQ(u2.getHour(), 10); + TEST_ASSERT_EQ(u2.getMinute(), 2); + TEST_ASSERT_EQ(u2.getSecond(), 42.24); + + // test YYYY:MM:DD constructor + sys::LocalDateTime l3(2000, 1, 1); + TEST_ASSERT_EQ(l3.getYear(), 2000); + TEST_ASSERT_EQ(l3.getMonth(), 1); + TEST_ASSERT_EQ(l3.getDayOfMonth(), 1); + TEST_ASSERT_EQ(l3.getDayOfYear(), 1); + + // test YYYY:MM:DD constructor + sys::UTCDateTime u3(2000, 1, 1); + TEST_ASSERT_EQ(u3.getYear(), 2000); + TEST_ASSERT_EQ(u3.getMonth(), 1); + TEST_ASSERT_EQ(u3.getDayOfMonth(), 1); + TEST_ASSERT_EQ(u3.getDayOfYear(), 1); + + // test YYYY:MM:DD:H:M:S constructor + sys::LocalDateTime l4(2012, 9, 17, 8, 22, 43.0); + TEST_ASSERT_EQ(l4.getYear(), 2012); + TEST_ASSERT_EQ(l4.getMonth(), 9); + TEST_ASSERT_EQ(l4.getDayOfMonth(), 17); + TEST_ASSERT_EQ(l4.getDayOfYear(), 261); + TEST_ASSERT_EQ(l4.getHour(), 8); + TEST_ASSERT_EQ(l4.getMinute(), 22); + TEST_ASSERT_EQ(l4.getSecond(), 43.0); + + // test YYYY:MM:DD:H:M:S constructor + sys::UTCDateTime u4(2012, 9, 17, 8, 22, 43.0); + TEST_ASSERT_EQ(u4.getYear(), 2012); + TEST_ASSERT_EQ(u4.getMonth(), 9); + TEST_ASSERT_EQ(u4.getDayOfMonth(), 17); + TEST_ASSERT_EQ(u4.getDayOfYear(), 261); + TEST_ASSERT_EQ(u4.getHour(), 8); + TEST_ASSERT_EQ(u4.getMinute(), 22); + TEST_ASSERT_EQ(u4.getSecond(), 43.0); +} + +} + +int main(int argc, char* argv[]) +{ + TEST_CHECK(testDefaultConstructor); + TEST_CHECK(testParameterizedConstructor); + + return 0; +} + diff --git a/modules/c++/sys/unittests/test_os.cpp b/modules/c++/sys/unittests/test_os.cpp new file mode 100644 index 000000000..0b27de462 --- /dev/null +++ b/modules/c++/sys/unittests/test_os.cpp @@ -0,0 +1,45 @@ +#include + +#include +#include + +#include "TestCase.h" + +namespace +{ +void createFile(const std::string& pathname) +{ + std::ofstream oss(pathname.c_str()); + oss.close(); +} + +TEST_CASE(testRecursiveRemove) +{ + // This assumes the user has write permissions in their current directory + const sys::OS os; + const sys::Path subdir1("subdir1"); + TEST_ASSERT( os.makeDirectory(subdir1) ); + createFile(subdir1.join("tempFile1")); + createFile(subdir1.join("tempFile2")); + + const sys::Path subdir2(subdir1.join("subdir2")); + TEST_ASSERT( os.makeDirectory(subdir2) ); + + const sys::Path subdir3(subdir2.join("subdir3")); + TEST_ASSERT( os.makeDirectory(subdir3) ); + createFile(subdir3.join("tempFile3")); + createFile(subdir3.join("tempFile4")); + createFile(subdir3.join("tempFile5")); + + // Try to recursively remove from the top level + TEST_ASSERT( os.remove(subdir1) ); + TEST_ASSERT( !os.exists(subdir1) ); +} +} + +int main(int argc, char** argv) +{ + TEST_CHECK(testRecursiveRemove); + + return 0; +} diff --git a/modules/c++/sys/wscript b/modules/c++/sys/wscript new file mode 100644 index 000000000..a98ee4004 --- /dev/null +++ b/modules/c++/sys/wscript @@ -0,0 +1,12 @@ +NAME = 'sys' +MAINTAINER = 'jmrandol@users.sourceforge.net' +VERSION = '1.2' +MODULE_DEPS = 'str except' +USELIB = 'THREAD DL RT SOCKET' +TEST_FILTER = 'MMapReadOnlyTest.cpp ProcessTest1.cpp' + +options = configure = distclean = lambda p: None + +def build(bld): + bld.module(**globals()) + diff --git a/modules/c++/tiff/include/import/tiff.h b/modules/c++/tiff/include/import/tiff.h new file mode 100644 index 000000000..d7cfdd19a --- /dev/null +++ b/modules/c++/tiff/include/import/tiff.h @@ -0,0 +1,40 @@ +/* ========================================================================= + * This file is part of tiff-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2011, General Dynamics - Advanced Information Systems + * + * tiff-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __IMPORT_TIFF_H__ +#define __IMPORT_TIFF_H__ + +#include "tiff/Common.h" +#include "tiff/Header.h" +#include "tiff/GenericType.h" +#include "tiff/IFDEntry.h" +#include "tiff/IFD.h" +#include "tiff/KnownTags.h" +#include "tiff/TypeFactory.h" +#include "tiff/ImageReader.h" +#include "tiff/FileReader.h" +#include "tiff/ImageWriter.h" +#include "tiff/FileWriter.h" +#include "tiff/Utils.h" + +#endif + diff --git a/modules/c++/tiff/include/tiff/Common.h b/modules/c++/tiff/include/tiff/Common.h new file mode 100644 index 000000000..7896eb3e1 --- /dev/null +++ b/modules/c++/tiff/include/tiff/Common.h @@ -0,0 +1,307 @@ +/* ========================================================================= + * This file is part of tiff-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2011, General Dynamics - Advanced Information Systems + * + * tiff-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +/** + ********************************************************************* + * @file + * @brief Contains classes for handling TIFF files. + *********************************************************************/ +#ifndef __TIFF_COMMON_H__ +#define __TIFF_COMMON_H__ + +#include +#include +#include + +namespace tiff +{ + +/** + ********************************************************************* + * @class Const + * @brief Contains constants used by TIFF files. + * + * Constants such as TIFF types, type sizes, and others have been + * pooled together into this class. Every member can be accessed + * statically so there is no need to create in instance of this class + * to use the constants. + *********************************************************************/ +class Const +{ +public: + //! Default constructor + Const() + { + } + + //! Deconstructor + ~Const() + { + } + + /** + ***************************************************************** + * @class Type + * @brief Contains an enumeration of every element type that TIFF + * supports. + *****************************************************************/ + class Type + { + public: + enum + { + NOTYPE = 0, + BYTE, + ASCII, + SHORT, + LONG, + RATIONAL, + SBYTE, + UNDEFINED, + SSHORT, + SLONG, + SRATIONAL, + FLOAT, + DOUBLE, + MAX + }; + }; + + /** + ***************************************************************** + * @class Type + * @brief Contains an enumeration of every sample format type. + *****************************************************************/ + class SampleFormatType + { + public: + enum + { + UNSIGNED_INT = 1, + SIGNED_INT, + IEEE_FLOAT, + UNDEFINED + }; + }; + + /** + ***************************************************************** + * @class Type + * @brief Contains an enumeration of every photometric + * interpretation type. + *****************************************************************/ + class PhotoInterpType + { + public: + enum + { + WHITE_IS_ZERO, + BLACK_IS_ZERO, + RGB, + COLORMAP, + TRANSPARENCY_MASK + }; + }; + + + /* + * Compression + * http://www.awaresystems.be/imaging/tiff/tifftags/compression.html + */ + + class CompressionType + { + public: + enum + { + NO_COMPRESSION = 1, + CCITT_HUFFMAN, + CCITT_G3_FAX, + CCITT_G4_FAX, + LZW, + JPEG_OLD, + JPEG, + DEFLATE, + JBIG_BW, + JBIG_COLOR, + PACK_BITS = 32773 + }; + }; + + + /** + ***************************************************************** + * Returns the size of the specified TIFF type. + * + * @param type + * The TIFF type to return the size of + * @return + * The size of the specified TIFF type + *****************************************************************/ + static short sizeOf(unsigned short type) + { + return mTypeSizes[type]; + } + +private: + //! The array of sizes for each TIFF type. + static short mTypeSizes[Type::MAX]; +}; + +/** + ********************************************************************* + * @class PrintStrategy + * @brief A strategy that defines how to print data. + * + * Most TIFF types will use this print strategy that simply converts + * the data to a string. + *********************************************************************/ +class PrintStrategy +{ +public: + //! Default constructor + PrintStrategy() + { + } + + //! Deconstructor + ~PrintStrategy() + { + } + + /** + ***************************************************************** + * Returns the string form of the data passed in. Used to make + * numbers printable without using printf(). + * + * @param data + * the data to convert to a string + * @return + * the data in string format + *****************************************************************/ + template static std::string toString(const T& data) + { + std::stringstream tempStream; + tempStream << data; + std::string output(tempStream.str()); + return output; + } +}; + +/** + ******************************************************************* + * @class RationalPrintStrategy + * @brief A strategy that defines how to print data for rational + * values. + * + * This print strategy is used to convert rational values into a + * printable string. It divides the numerator by the denominator + * and returns the string form of the result. + *******************************************************************/ +class RationalPrintStrategy +{ +public: + //! Default Constructor + RationalPrintStrategy() {} + + //! Constructor + ~RationalPrintStrategy() + { + } + + /** + ************************************************************* + * Converts the specified data to a string. Both numerator + * and denominator are signed longs. + * + * @param data + * the data to convert to a string. + * @return + * the string form of the rational number + *************************************************************/ + static std::string toString(const sys::Uint32_T data); + +}; + +/** + ***************************************************************** + * Combines a numerator and a denominator into a single data + * type. The numerator is placed in the top 4 bytes, and the + * denominator in the bottom 4 bytes of the returned sys::Uint64_T. + * + * @param numerator + * the numerator + * @param denominator + * the denominator + * @return + * the combined rational number + *****************************************************************/ +sys::Uint64_T combine(sys::Uint32_T numerator, sys::Uint32_T denominator); + +/** + ***************************************************************** + * Combines a numerator and a denominator into a single data + * type. The numerator is placed in the top 4 bytes, and the + * denominator in the bottom 4 bytes of the returned unsigned + * sys::Uint32_T. + * + * @param numerator + * the numerator + * @param denominator + * the denominator + * @return + * the combined rational number + *****************************************************************/ +sys::Uint64_T combine(sys::Uint32_T numerator, sys::Uint32_T denominator); + +/** + ***************************************************************** + * Splits the 'value' parameter into a numerator and a + * denominator. + * + * @param value + * the rational number to split into parts + * @param numerator + * the returned numerator + * @param denominator + * the returned denominator + *****************************************************************/ +//void split(sys::Uint32_T value, sys::Uint32_T &numerator, sys::Uint32_T &denominator); + +/** + ***************************************************************** + * Splits the 'value' parameter into a numerator and a + * denominator. + * + * @param value + * the rational number to split into parts + * @param numerator + * the returned numerator + * @param denominator + * the returned denominator + *****************************************************************/ +void split(sys::Uint64_T value, sys::Uint32_T &numerator, + sys::Uint32_T &denominator); + +} // End namespace tiff. + +#endif // __TIFF_COMMON_H__ diff --git a/modules/c++/tiff/include/tiff/FileReader.h b/modules/c++/tiff/include/tiff/FileReader.h new file mode 100644 index 000000000..2644245b2 --- /dev/null +++ b/modules/c++/tiff/include/tiff/FileReader.h @@ -0,0 +1,153 @@ +/* ========================================================================= + * This file is part of tiff-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2011, General Dynamics - Advanced Information Systems + * + * tiff-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __TIFF_FILE_READER_H__ +#define __TIFF_FILE_READER_H__ + +#include +#include +#include + +#include "tiff/Header.h" +#include "tiff/ImageReader.h" + +namespace tiff +{ + +/** + ********************************************************************* + * @class FileReader + * @brief Reads a TIFF file. + * + * Reads a TIFF file and all images within that file. Has functions + * to access a specific image within the file, and to read data from + * a specific image in the file. + *********************************************************************/ +class FileReader +{ +public: + + //! Constructor + FileReader() + { + } + + /** + ***************************************************************** + * Constructor. Opens and parses the specified file as a TIFF + * file. + * + * @param fileName + * the file to open and parse as a TIFF file + * @todo + * ios::nocreate missing in newer G++ + *****************************************************************/ + FileReader(const std::string& fileName) + { + openFile(fileName); + } + + //! Destructor + ~FileReader() + { + close(); + } + + /** + ***************************************************************** + * Processes the TIFF file. Reads the TIFF header, and every + * IFD the file has, creating a new ImageReader for each. + *****************************************************************/ + void openFile(const std::string& fileName); + + //! Closes the TIFF file and clears out member data. + void close(); + + /** + ***************************************************************** + * Retrieves an ImageReader pointer to the specified image. + * + * @param index + * the numeric index of the image to retrieve + * @return + * an ImageReader pointer to the specified image + *****************************************************************/ + tiff::ImageReader *operator[](const sys::Uint32_T index) const; + + /** + ***************************************************************** + * Prints the the file's header, and every image's IFD to the + * specified output stream. + * + * @param output + * the stream to print the file information to + *****************************************************************/ + void print(io::OutputStream &output) const; + + /** + ***************************************************************** + * Gets the specified number of elements from the TIFF image and + * stores them into the specified buffer. The buffer must be + * allocated outside because it is not allocated in this function. + * + * @param buffer + * the buffer to populate with image data + * @param numElementsToRead + * the number of elements (not bytes) to read from the image + * @param subSourceIndex + * the index of the image within the file to read from + *****************************************************************/ + void getData(unsigned char *buffer, const sys::Uint32_T numElementsToRead, + const sys::Uint32_T subSourceIndex = 0); + + /** + ***************************************************************** + * Returns the number of images in the TIFF file. + * + * @return + * the number of images in the TIFF file + *****************************************************************/ + sys::Uint32_T getImageCount() const + { + return mImages.size(); + } + + +private: + + //! The input stream to use to read the TIFF file + io::FileInputStream mInput; + + //! The TIFF file header + tiff::Header mHeader; + + //! The images within the TIFF file + std::vector mImages; + + //! Whether to reverse bytes while reading. + bool mReverseBytes; + +}; + +} // End namespace. + +#endif // __TIFF_FILE_READER_H__ diff --git a/modules/c++/tiff/include/tiff/FileWriter.h b/modules/c++/tiff/include/tiff/FileWriter.h new file mode 100644 index 000000000..298b3c0aa --- /dev/null +++ b/modules/c++/tiff/include/tiff/FileWriter.h @@ -0,0 +1,264 @@ +/* ========================================================================= + * This file is part of tiff-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2011, General Dynamics - Advanced Information Systems + * + * tiff-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __TIFF_FILE_WRITER_H__ +#define __TIFF_FILE_WRITER_H__ + +#include +#include +#include +#include "tiff/Header.h" +#include "tiff/ImageWriter.h" + +namespace tiff +{ + +/** + ********************************************************************* + * @class FileWriter + * @brief Writes a TIFF file. + * + * Writes a TIFF file to an output stream. Can write multiple images + * to the same file. Contains function for manipulating each + * sub-image and for writing data. + *********************************************************************/ +class FileWriter +{ +public: + + //! Constructor + FileWriter() : + mIFDOffset(0) + { + } + + /** + ***************************************************************** + * Constructor. Opens the specified file name for writing. + * + * @param fileName + * the file to open for writing + *****************************************************************/ + FileWriter(const std::string& fileName) : + mIFDOffset(0) + { + openFile(fileName); + } + + //! Destructor + ~FileWriter(); + + void openFile(const std::string& fileName); + void close(); + + /** + ***************************************************************** + * Retrieves a ImageWriter pointer to the specified image. + * + * @param index + * the numeric index of the image to retrieve + * @return + * a TIFFImageWriter pointer to the specified image + *****************************************************************/ + tiff::ImageWriter *operator[](const sys::Uint32_T index) const; + + /** + ***************************************************************** + * Writes data to the output file stream. The input buffer + * must be in raster format. Converts raster data to either + * tiled or stripped format. + * + * @param buffer + * the buffer to write to the output stream + * @param numElementsToWrite + * the number of elements (not bytes) to write + * @param subImageIndex + * the index to a sub-image to write + *****************************************************************/ + void putData(const unsigned char *buffer, + sys::Uint32_T numElementsToWrite, + sys::Uint32_T subImageIndex = 0); + + /** + ***************************************************************** + * Creates and adds an image to the TIFF file. Sets necessary + * defaults within the image and returns a pointer to that image + * so that the user can manipulate its IFD. + * + * @return + * A pointer to a TIFF image. + *****************************************************************/ + tiff::ImageWriter *addImage(); + + /** + ***************************************************************** + * Writes the TIFF header to the file. There is only one header + * in a TIFF file regardless of how many images are in it. + *****************************************************************/ + void writeHeader(); + + +private: + // Noncopyable + FileWriter(const FileWriter& ); + const FileWriter& operator=(const FileWriter& ); + +private: + //! The position to write the offset to the first IFD to + sys::Uint32_T mIFDOffset; + + //! The output stream + io::FileOutputStream mOutput; + + //! The TIFF header + tiff::Header mHeader; + + //! The images to write + std::vector mImages; + +}; + +/** Enumeration for automatic detection of image type */ +enum { AUTO = -1 }; + +/*! + * This function is designed to mimic (roughly) the API for sio::lite::writeSIO(). + * It attempts to automatically guess the correct TIFF type for an input image, + * and write as a TIFF file. + * + * Unlike the writeSIO function, this function does not support complex pixels, + * and will end up writing them as IEEE_FLOAT, which is probably not the desired + * behavior, so care is required. The supported types are double, float, RGB + * 3-byte unsigned, and single unsigned byte (mono). + * + * Most TIFF viewers will not support float files, and therefore, it may be more + * desirable to remap float data to bytes prior to calling this routine. + * + * \param image The data to write to TIFF + * \param rows The number of rows in image + * \param cols The number of cols in image + * \param imageFile The name of the file + * \param et The element type, which can be any tiff::Const::SampleFormatType, or + * defaults to automatically guessing based on the input data size + * \param es The element size, which can be any size, but defaults to automatically + * guessing based on the input data size + * + */ +template void writeTIFF(const T* image, size_t rows, size_t cols, + std::string imageFile, unsigned short et = AUTO, int es = AUTO) +{ + + if (es == AUTO) + es = sizeof(T); + + unsigned int photoInterp(1); + unsigned short numBands(1); + + if (et == static_cast(AUTO)) + { + switch (es) + { + case 8: + et = ::tiff::Const::SampleFormatType::IEEE_FLOAT; + numBands = 2; + break; + + case 4: + et = ::tiff::Const::SampleFormatType::IEEE_FLOAT; + break; + + case 3: + et = ::tiff::Const::SampleFormatType::UNSIGNED_INT; + photoInterp = (unsigned short) ::tiff::Const::PhotoInterpType::RGB; + numBands = 3; + break; + + case 1: + et = ::tiff::Const::SampleFormatType::UNSIGNED_INT; + break; + default: + throw except::Exception(Ctxt(FmtX("Unexpected es: %d", es))); + } + } + unsigned short alpha(0); + if (es == 4 && et == ::tiff::Const::SampleFormatType::UNSIGNED_INT) + { + photoInterp = (unsigned short) ::tiff::Const::PhotoInterpType::RGB; + numBands = 4; + // This is "unassociated alpha value" + alpha = 2; + + } + + + ::tiff::FileWriter fileWriter(imageFile); + + //write the header first + fileWriter.writeHeader(); + + + ::tiff::ImageWriter* imageWriter = fileWriter.addImage(); + ::tiff::IFD* ifd = imageWriter->getIFD(); + + ifd->addEntry(::tiff::KnownTags::IMAGE_WIDTH, cols); + ifd->addEntry(::tiff::KnownTags::IMAGE_LENGTH, rows); + + ifd->addEntry(::tiff::KnownTags::COMPRESSION, + (unsigned short) ::tiff::Const::CompressionType::NO_COMPRESSION); + + + ifd->addEntry(::tiff::KnownTags::PHOTOMETRIC_INTERPRETATION, photoInterp); + // Added this for RGBA, because otherwise the ImageWriter::validate() changes all of + // these fields back assuming 3 bytes per pixel + ifd->addEntry(::tiff::KnownTags::SAMPLES_PER_PIXEL, numBands); + ifd->addEntry(::tiff::KnownTags::BITS_PER_SAMPLE); + ifd->addEntry(::tiff::KnownTags::SAMPLE_FORMAT); + ::tiff::IFDEntry* bps = (*ifd)[::tiff::KnownTags::BITS_PER_SAMPLE]; + ::tiff::IFDEntry* sf = (*ifd)[::tiff::KnownTags::SAMPLE_FORMAT]; + + unsigned short bitsPerBand = (es << 3) / numBands; + + //set some fields that have 'numSamples' values + for (int band = 0; band < numBands; ++band) + { + bps->addValue(::tiff::TypeFactory::create((unsigned char *) &bitsPerBand, + ::tiff::Const::Type::SHORT)); + sf->addValue(::tiff::TypeFactory::create((unsigned char *) &et, + ::tiff::Const::Type::SHORT)); + } + + // If the alpha channel is on (note 0 is a valid value for ExtraSamples, + // but Im using it to be boolean (0 = off) and the unassociated value here + if (alpha) + ifd->addEntry(std::string("ExtraSamples"), alpha); + + imageWriter->putData((unsigned char*) image, rows * cols); + + //write the IFD + imageWriter->writeIFD(); + fileWriter.close(); + +} + +} // End namespace. + +#endif // __TIFF_FILE_WRITER_H__ diff --git a/modules/c++/tiff/include/tiff/GenericType.h b/modules/c++/tiff/include/tiff/GenericType.h new file mode 100644 index 000000000..2e8fefa74 --- /dev/null +++ b/modules/c++/tiff/include/tiff/GenericType.h @@ -0,0 +1,182 @@ +/* ========================================================================= + * This file is part of tiff-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2011, General Dynamics - Advanced Information Systems + * + * tiff-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __TIFF_GENERIC_TYPE_H__ +#define __TIFF_GENERIC_TYPE_H__ + +#include +#include + +#include "tiff/Common.h" + +namespace tiff +{ + +/** + ********************************************************************* + * @class TypeInterface + * @brief The interface class that all TIFF types inherit from. + *********************************************************************/ +class TypeInterface : public io::Serializable +{ +public: + //! Default constructor + TypeInterface() + { + } + + //! Deconstructor + virtual ~TypeInterface() + { + } + + /** + ***************************************************************** + * Returns the data of the TIFF type in byte format. + * + * @return + * the data in byte format + *****************************************************************/ + virtual unsigned char *data() const = 0; + + /** + ***************************************************************** + * Returns the size of the TIFF type. + * + * @return + * the size of the TIFF type + *****************************************************************/ + virtual unsigned short size() const = 0; + + /** + ***************************************************************** + * Converts the data to a string representation of it. + * + * @return + * the string representation of the data + *****************************************************************/ + virtual std::string toString() const = 0; +}; + +/** + ********************************************************************* + * @class GenericType + * @brief A templated TIFF type for abstracting data types. + * + * Stores data as the templatized type. All TIFF types can then + * be treated as a single type with a different data member. Contains + * functions for reading and writing the data to a stream, converting + * the data to a string for printing, and retrieving the data in + * byte form. + *********************************************************************/ +template class GenericType : + public TypeInterface +{ +public: + //! Default constructor + GenericType() : + mData(0) + { + } + + explicit GenericType(std::string s) : + mData(str::toType(s)) + { + } + + /** + ***************************************************************** + * Constructor, initializes the object with the specified data. + * + * @param data + * the data to initialize the object with + *****************************************************************/ + GenericType(const unsigned char *data) + { + mData = *((Data_T *)data); + } + + //! Deconstructor + virtual ~GenericType() + { + } + + /** + ***************************************************************** + * Writes the data member to the specified stream. + * + * @param output + * the output stream to write the member to + *****************************************************************/ + virtual void serialize(io::OutputStream& output) + { + output.write((char *)&mData, sizeof(Data_T)); + } + + /** + ***************************************************************** + * Reads the data member from the specified stream. + * + * @param input + * the input stream to read the member from + *****************************************************************/ + virtual void deserialize(io::InputStream& input) + { + input.read((char *)&mData, sizeof(Data_T)); + } + + virtual unsigned char *data() const + { + return (unsigned char *)&mData; + } + + virtual unsigned short size() const + { + return sizeof(mData); + } + + virtual std::string toString() const + { + return Strategy_T::toString(mData); + } + + /** + ***************************************************************** + * Casting operator. Returns the data in its native type. + * + * @return + * the member data in the native type + *****************************************************************/ + operator Data_T() const + { + return mData; + } + +protected: + + //! The member data + Data_T mData; +}; + +} // End namespace. + +#endif // __TIFF_GENERIC_TYPE_H__ diff --git a/modules/c++/tiff/include/tiff/Header.h b/modules/c++/tiff/include/tiff/Header.h new file mode 100644 index 000000000..5a3f366c6 --- /dev/null +++ b/modules/c++/tiff/include/tiff/Header.h @@ -0,0 +1,147 @@ +/* ========================================================================= + * This file is part of tiff-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2011, General Dynamics - Advanced Information Systems + * + * tiff-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __TIFF_HEADER_H__ +#define __TIFF_HEADER_H__ + +#include +#include "tiff/Common.h" + +namespace tiff +{ + +/** + ********************************************************************* + * @class Header + * @brief Contains TIFF header information + *********************************************************************/ +class Header : public io::Serializable +{ +public: + enum ByteOrder { MM, II }; + + /** + ***************************************************************** + * Constructor. Allows the user to set the values in the header + * and also provides resonable defaults. + * + * @param id + * the TIFF identifier, always "42" + * @param byteOrder + * the byte order of the file "MM" for Big Endian, "II" + * for Little Endian + * @param ifdOffset + * the offset to the first IFD + *****************************************************************/ + Header(const unsigned short id = 42, const char byteOrder[2] = " ", + const sys::Uint32_T ifdOffset = 8) : + mId(id), mIFDOffset(ifdOffset) + { + bool isBigEndian = sys::isBigEndianSystem(); + if (byteOrder[0] == ' ' && byteOrder[1] == ' ') + { + //set it based on the system + strncpy(mByteOrder, isBigEndian ? "MM" : "II", 2); + } + else + strncpy(mByteOrder, byteOrder, 2); + + mDifferentByteOrdering = isBigEndian ? \ + getByteOrder() != MM : getByteOrder() != II; + } + + //! Destructor + ~Header() + { + } + + /** + ***************************************************************** + * Writes the TIFF header to the specified output stream. + * + * @param output + * the stream to write the header to + *****************************************************************/ + void serialize(io::OutputStream& output); + + /** + ***************************************************************** + * Reads the TIFF header from the specified input stream. + * + * @param input + * the stream to read the header from + *****************************************************************/ + void deserialize(io::InputStream& input); + + /** + ***************************************************************** + * Prints the TIFF header to the specified output stream in + * string format. + * + * @param output + * the stream to print the header to + *****************************************************************/ + void print(io::OutputStream& output) const; + + /** + ***************************************************************** + * Retrieves the offset to the IFD. + * + * @return + * the IFD offset + *****************************************************************/ + sys::Uint32_T getIFDOffset() const + { + return mIFDOffset; + } + + ByteOrder getByteOrder() const + { + if (mByteOrder[0] == 'M' && mByteOrder[1] == 'M') + return MM; + + return II; + } + + bool isDifferentByteOrdering() + { + return mDifferentByteOrdering; + } + +private: + + //! The byte order + char mByteOrder[2]; + + //! The TIFF identifier + unsigned short mId; + + //! The IFD offset + sys::Uint32_T mIFDOffset; + + bool mDifferentByteOrdering; + +}; + +} // End namespace. + +#endif // __TIFF_HEADER_H__ diff --git a/modules/c++/tiff/include/tiff/IFD.h b/modules/c++/tiff/include/tiff/IFD.h new file mode 100644 index 000000000..ea497e1e7 --- /dev/null +++ b/modules/c++/tiff/include/tiff/IFD.h @@ -0,0 +1,311 @@ +/* ========================================================================= + * This file is part of tiff-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2011, General Dynamics - Advanced Information Systems + * + * tiff-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __TIFF_IFD_H__ +#define __TIFF_IFD_H__ + +#include +#include +#include +#include + +#include "tiff/IFDEntry.h" +#include "tiff/KnownTags.h" +#include "tiff/TypeFactory.h" + +namespace tiff +{ + +/** + ********************************************************************* + * @class IFD + * @brief The TIFF IFD class. Contains all IFD Entries for an image. + * + * This is basically the TIFF footer for every TIFF image. Each + * entry in it further defines the image it is associated with. + * Contains functions for adding new entries to the IFD or adding + * values to a specific IFD entry. + *********************************************************************/ +class IFD : public io::Serializable +{ +public: + //! The IFDType + typedef std::map IFDType; + + //! Constructor + IFD() : + mNextIFDOffsetPosition(0) + { + } + + //! Deconstructor + ~IFD() + { + for (sys::Uint32_T i = 0; i < mIFD.size(); ++i) + delete mIFD[i]; + } + + /** + ***************************************************************** + * Retrieves a pointer to the IFDEntry associated with the + * specified name. + * + * @param name + * the name to look for in the IFD. + * @return + * the TIFFIFDEntry associated with the specified name, or + * NULL if the entry doesn't exist in the IFD + *****************************************************************/ + tiff::IFDEntry *operator[](const char *name); + + tiff::IFDEntry *operator[](const std::string& name) + { + return this->operator[](name.c_str()); + } + + /** + ***************************************************************** + * Retrieves a pointer to the IFDEntry associated with the + * specified tag. + * + * @param name + * the tag to look for in the IFD. + * @return + * the TIFFIFDEntry associated with the specified tag, or + * NULL if the entry doesn't exist in the IFD + *****************************************************************/ + tiff::IFDEntry *operator[](unsigned short tag); + + /** + * Returns true if an IFDEntry for the given tag exists in the IFD. + * \return true if the entry exists, otherwise false. + */ + bool exists(unsigned short tag); + + /** + * Returns true if an IFDEntry with the given name exists in the IFD. + * \return true if the entry exists, otherwise false. + */ + bool exists(const char *name); + + /** + * Returns true if an IFDEntry with the given name exists in the IFD. + * \return true if the entry exists, otherwise false. + */ + bool exists(const std::string& name) + { + return exists(name.c_str()); + } + + /** + ***************************************************************** + * Adds the specified IFDEntry to the IFD. Makes a copy of + * the IFD entry passed in. + * + * @param entry + * the IFDEntry to copy into the IFD + *****************************************************************/ + void addEntry(const tiff::IFDEntry *entry); + + /** + ***************************************************************** + * Adds an IFDEntry with the specified name to the IFD. Looks + * up the specified name in the KnownTagsSingleton. + * + * @param name + * the name of the IFDEntry to copy into the IFD + *****************************************************************/ + void addEntry(const std::string& name); + + /** + ***************************************************************** + * Adds a IFDEntry with the specified name to the IFD. Looks + * up the specified name in the KnownTags Singleton. Adds the + * specified value to the added IFDEntry. + * + * @param name + * the name of the IFDEntry to copy into the IFD + * @param value + * the value to add to the IFDEntry + *****************************************************************/ + template void addEntry(const std::string& name, const T& value) + { + tiff::IFDEntry *mapEntry = tiff::KnownTagsRegistry::getInstance()[name]; + //we can't add it if we don't know about it + if (!mapEntry) + throw except::Exception(Ctxt(FmtX( + "Unable to add IFD Entry: unknown tag [%s]", name.c_str()))); + + unsigned short id = mapEntry->getTagID(); + unsigned short type = mapEntry->getType(); + + mIFD[id] = new tiff::IFDEntry; + *(mIFD[id]) = *mapEntry; + mIFD[id]->addValue(tiff::TypeFactory::create( (unsigned char *)&value, + type)); + } + + /** + ***************************************************************** + * Looks up the specified name in the IFD. If it exists, will + * add the specified value to the associated IFD entry. + * + * @param name + * the name of the IFDEntry to copy into the IFD + * @param value + * the value to add to the IFDEntry + *****************************************************************/ + template void addEntryValue(const std::string& name, + const T value) + { + tiff::IFDEntry *entry = (*this)[name.c_str()]; + if (!entry) + throw except::Exception(Ctxt("IFD entry must exist before adding values")); + + entry->addValue(tiff::TypeFactory::create((unsigned char *)&value, + entry->getType())); + } + + /** + ***************************************************************** + * Writes the complete IFD to the specified output stream. + * + * @param output + * the output stream to write the IFD to + *****************************************************************/ + void serialize(io::OutputStream& output); + + /** + ***************************************************************** + * Reads the complete IFD from the specified input stream. + * + * @param input + * the input stream to read the IFD from + *****************************************************************/ + void deserialize(io::InputStream& input); + void deserialize(io::InputStream& input, const bool reverseBytes); + + /** + ***************************************************************** + * Prints the complete IFD out to the specified output stream in + * a readable format. + * + * @param output + * the output stream to print the IFD to + *****************************************************************/ + void print(io::OutputStream& output) const; + + /** + ***************************************************************** + * Returns the number of IFD entries in the IFD. + * + * @return + * the number of IFD entries in the IFD + *****************************************************************/ + sys::Uint32_T size() + { + return mIFD.size(); + } + + /** + ***************************************************************** + * Calculates the image size in bytes from entries in the IFD and + * returns the value. + * + * @return + * the calculated image size in bytes + *****************************************************************/ + sys::Uint32_T getImageSize(); + + /** + ***************************************************************** + * Calculates the image width in elements from entries in the + * IFD and returns the value. + * + * @return + * the calculated image width in elements + *****************************************************************/ + sys::Uint32_T getImageWidth(); + + /** + ***************************************************************** + * Calculates the image length in lines from entries in the + * IFD and returns the value. + * + * @return + * the calculated image length in lines + *****************************************************************/ + sys::Uint32_T getImageLength(); + + /** + ***************************************************************** + * Calculates the element size in bytes from entries in the + * IFD and returns the value. + * + * @return + * the calculated element size in bytes + *****************************************************************/ + unsigned short getElementSize(); + + + unsigned short getNumBands(); + + /** + ***************************************************************** + * Returns the file offset where the offset to the next IFD can + * be written. + * + * @return + * the offset to write the next IFD offset to + *****************************************************************/ + sys::Uint32_T getNextIFDOffsetPosition() + { + return mNextIFDOffsetPosition; + } + +private: + + /** + ***************************************************************** + * Finalizes all of the IFD entries. Calculates the file offsets + * of every IFD entry that has overflow data and sets that offset + * into each entry. + * + * @param offset + * the file offset that indicates the beginning position of + * the IFD. + * @return + * the highest overflow offset calculated, this marks the + * potential beginning of the next image. + *****************************************************************/ + sys::Uint32_T finalize(const sys::Uint32_T offset); + + //! The IFD entries + IFDType mIFD; + + //! Offset where the next IFD offset can be written to + sys::Uint32_T mNextIFDOffsetPosition; +}; + +} // End namespace. + +#endif // __TIFF_IFD_H__ diff --git a/modules/c++/tiff/include/tiff/IFDEntry.h b/modules/c++/tiff/include/tiff/IFDEntry.h new file mode 100644 index 000000000..ca885fd89 --- /dev/null +++ b/modules/c++/tiff/include/tiff/IFDEntry.h @@ -0,0 +1,394 @@ +/* ========================================================================= + * This file is part of tiff-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2011, General Dynamics - Advanced Information Systems + * + * tiff-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#ifndef __TIFF_IFD_ENTRY_H__ +#define __TIFF_IFD_ENTRY_H__ + +#include +#include +#include +#include +#include "tiff/GenericType.h" + +namespace tiff +{ + +/** + ********************************************************************* + * @class IFDEntry + * @brief Contains all the information for an IFD entry + * + * A TIFF IFD entry is basically a footer entry. It keeps track of + * information about the image such as image width, or element size. + * Provides a container for storing TIFF IFD entry information. This + * includes all of the data associated with an IFD entry. There are + * functions for printing out the entry, reading and writing it to a + * file, and accessing the data. + *********************************************************************/ +class IFDEntry : public io::Serializable +{ +public: + //! Constructor + IFDEntry() : + mTag(0), mType(0), mCount(0), mOffset(0) + { + } + + /** + ***************************************************************** + * Constructor. Allows the user to specify the tag id, type, + * name and the number of values it has. + * + * @param tag + * the numeric identifier for this entry + * @param type + * the data type for this entry (see TIFFConst::Type) + * @param name + * the name of this entry (i.e. "ImageWidth") + * @param count + * the number of values for this entry + *****************************************************************/ + IFDEntry(const unsigned short tag, const unsigned short type, + const std::string& name, const sys::Uint32_T count = 0) : + mTag(tag), mType(type), mCount(count), mOffset(0), mName(name) + { + } + + /** + ***************************************************************** + * Constructor. Allows the user to specify the tag id, type, + * and the number of values it has. + * + * @param tag + * the numeric identifier for this entry + * @param type + * the data type for this entry (see TIFFConst::Type) + * @param count + * the number of values for this entry + *****************************************************************/ + IFDEntry(const unsigned short tag, const unsigned short type, + const sys::Uint32_T count = 0) : + mTag(tag), mType(type), mCount(count), mOffset(0) + { + } + + //! Deconstructor + ~IFDEntry() + { + for (sys::Uint32_T i = 0; i < mValues.size(); ++i) + delete mValues[i]; + } + + /** + ***************************************************************** + * Returns the value at the specified index. + * + * @param index + * the index that indicates which value to retrieve + * @return + * the value at the specified index, or NULL + *****************************************************************/ + tiff::TypeInterface *operator[](const sys::Uint32_T index) const + { + return mValues[index]; + } + + /** + ***************************************************************** + * Writes the IFD entry to the specified output stream. + * + * @param output + * the output stream to write the entry to + *****************************************************************/ + void serialize(io::OutputStream& output); + + /** + ***************************************************************** + * Reads the IFD entry from the specified input stream. + * + * @param input + * the input stream to read the entry from + *****************************************************************/ + void deserialize(io::InputStream& input); + void deserialize(io::InputStream& input, const bool reverseBytes); + + /** + ***************************************************************** + * Prints the IFD entry in a readable format to the specified + * output stream. + * + * @param output + * the output stream to write the entry to + *****************************************************************/ + void print(io::OutputStream& output) const; + + /** + ***************************************************************** + * Returns the name of the IFD entry. + * + * @return + * the name of the IFD entry. + *****************************************************************/ + const std::string& getName() const + { + return mName; + } + + /** + ***************************************************************** + * Returns the name of the IFD entry. + * + * @return + * the name of the IFD entry. + *****************************************************************/ + std::string getName() + { + return mName; + } + + /** + ***************************************************************** + * Returns the type of the IFD entry. + * + * @return + * the type of the IFD entry. + *****************************************************************/ + unsigned short getType() const + { + return mType; + } + + /** + ***************************************************************** + * Returns the number of values in the IFD entry + * + * @return + * the number of values in the IFD entry. + *****************************************************************/ + sys::Uint32_T getCount() const + { + return mCount; + } + + /** + ***************************************************************** + * Returns the value offset. + * + * @return + * the value offset + *****************************************************************/ + sys::Uint32_T getOffset() const + { + return mOffset; + } + + /** + ***************************************************************** + * Returns the tag ID of the IFD entry. + * + * @return + * the tag ID of the IFD entry. + *****************************************************************/ + unsigned short getTagID() const + { + return mTag; + } + + /** + ***************************************************************** + * Returns the vector of values that are in the IFD entry. + * + * @return + * the vector of values in the IFD entry. + *****************************************************************/ + const std::vector& getValues() const + { + return mValues; + } + + /** + ***************************************************************** + * Returns the vector of values that are in the IFD entry. + * + * @return + * the vector of values in the IFD entry. + *****************************************************************/ + std::vector getValues() + { + return mValues; + } + + /** + ***************************************************************** + * Adds a value to the IFD entry, taking ownership. IFD Entries + * can have multiple values within them. + * + * @param value + * the tiff::GenericType to add as a value + *****************************************************************/ + void addValue(tiff::TypeInterface *value) + { + mValues.push_back(value); + ++mCount; + } + + /** + ***************************************************************** + * Adds a value to the IFD entry. IFD Entries can have multiple + * values within them. + * + * @param value + * the tiff::GenericType to add as a value + *****************************************************************/ + void addValue(std::auto_ptr value) + { + mValues.push_back(value.get()); + ++mCount; + value.release(); + } + + /** + ***************************************************************** + * Adds a double value to the IFD entry. + * + * @param value + * the double to add as a value + *****************************************************************/ + void addValue(double value); + + /** + ***************************************************************** + * Adds the same double value to the IFD entry multiple times. + * + * @param value + * the double to add as a value + * @param numValues + * the number of times to add the value + *****************************************************************/ + void addValue(double value, size_t numValues) + { + for (size_t ii = 0; ii < numValues; ++ii) + { + addValue(value); + } + } + + /** + ***************************************************************** + * Adds each character of the string as a value to the IFD entry. + * + * @param value + * the string to add as a series of values + * @param tiffType + * the type of the value to use. defaults to ascii. + *****************************************************************/ + void addValues(const char* str, int tiffType = Const::Type::ASCII); + + void addValues(const std::string& str, int tiffType = Const::Type::ASCII) + { + addValues(str.c_str(), tiffType); + } + + /** + ***************************************************************** + * Parses the specified buffer for values to store into the + * IFD entry. Sets the value count of the IFD entry to the + * specified count and uses it to determine how many values are in + * the buffer, and the type of the IFD entry to determine the size + * of each value. + * + * @param buffer + * the buffer to parse for values + * @param count + * the number of values in the buffer + *****************************************************************/ + void parseValues(const unsigned char *buffer, const sys::Uint32_T count); + + /** + ***************************************************************** + * Used for outputting the IFD entry to a file. Calculates + * a file offset to put data that overflows the size allowed for + * an IFD entry value (4 bytes) and sets the value count to be + * the number of values that were added to the IFD entry. + * + * @param offset + * the next free file offset that the values will can be + * written to + * @return + * the next free file offset, compensating for the IFD entry's + * values being written at the specified input offset + *****************************************************************/ + sys::Uint32_T finalize(const sys::Uint32_T offset); + + /** + ***************************************************************** + * According to the TIFF 6.0 spec, the size of an IFD entry is 12 + * bytes. The sizeof operator is thrown off by the extra members + * mName of string type, and mValues of vector type (both of which + * are not in the specification but exist to make life simpler), + * hence the adjustment. Returns the size of the IFD entry. + * + * @return + * the size of an IFD entry (12 bytes). + *****************************************************************/ + static unsigned short sizeOf() + { + return 12; + } + +private: + + /** + ***************************************************************** + * Parses the specified buffer for values to store into the + * IFD entry. Uses the value count of the IFD entry to determine + * how many values are in the buffer, and the type of the IFD + * entry to determine the size of each value. + * + * @param buffer + * the buffer to parse for values + *****************************************************************/ + void parseValues(const unsigned char *buffer); + + //! The TIFF tag identifier + unsigned short mTag; + + //! The TIFF type identifier + unsigned short mType; + + //! The number of values in the IFD entry + sys::Uint32_T mCount; + + //! The file offset to values for the IFD entry + sys::Uint32_T mOffset; + + //! The name of the IFD entry (i.e. "ImageWidth") + std::string mName; + + //! The values in this IFD entry + std::vector mValues; +}; + +} // End namespace. + +#endif // __TIFF_IFD_ENTRY_H__ diff --git a/modules/c++/tiff/include/tiff/ImageReader.h b/modules/c++/tiff/include/tiff/ImageReader.h new file mode 100644 index 000000000..82926c463 --- /dev/null +++ b/modules/c++/tiff/include/tiff/ImageReader.h @@ -0,0 +1,185 @@ +/* ========================================================================= + * This file is part of tiff-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2011, General Dynamics - Advanced Information Systems + * + * tiff-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __TIFF_IMAGE_READER_H__ +#define __TIFF_IMAGE_READER_H__ + +#include + +#include "tiff/IFDEntry.h" +#include "tiff/IFD.h" + +namespace tiff +{ + +/** + ********************************************************************* + * @class ImageReader + * @brief Reads a TIFF image + * + * Reads a TIFF image and parses out the IFD. Contains functions for + * getting data from the image and retrieving the TIFF IFD. + *********************************************************************/ +class ImageReader +{ +public: + /** + ***************************************************************** + * Constructor. Sets the image reader to read from the specified + * file stream. + * + * @param input + * the stream to read the TIFF image from + *****************************************************************/ + ImageReader(io::FileInputStream *input) : + mIFD(), mStripByteCounts(NULL), mStripOffsets(NULL), mInput(input), + mNextOffset(0), mBytePosition(0), mStripIndex(0), + mElementSize(0), mReverseBytes(false) + { + } + + //! Destructor + ~ImageReader() + { + } + + /** + ***************************************************************** + * Processes the image from the file. Reads the image's IFD + * and stores it for later use. + *****************************************************************/ + void process(const bool reverseBytes = false); + + /** + ***************************************************************** + * Prints the image's IFD to the specified output stream. + * + * @param output + * the stream to print the IFD to + *****************************************************************/ + void print(io::OutputStream &output) const; + + /** + ***************************************************************** + * Gets the specified number of elements from the TIFF image and + * stores them into the specified buffer. The buffer must be + * allocated outside because it is not allocated in this function. + * + * @param buffer + * the buffer to populate with image data + * @param numElementsToRead + * the number of elements (not bytes) to read from the image + *****************************************************************/ + void getData(unsigned char *buffer, const sys::Uint32_T numElementsToRead); + + /** + ***************************************************************** + * Returns a pointer to the IFD for this image. + * + * @return + * a pointer to the IFD for this image + *****************************************************************/ + tiff::IFD* getIFD() + { + return &mIFD; + } + + /** + ***************************************************************** + * Writes out any GeoTIFF information found in the IFD to the + * specified file. + * + * @param fileName + * the file to write the GeoTIFF information to + *****************************************************************/ + void writeGeoTIFFInfo(const std::string &fileName); + + /** + ***************************************************************** + * Returns the offset to the next IFD. Used to determine if + * there is another image in the file, and if so where is the + * file position of the next image's IFD. + * + * @return + * the next IFD offset + *****************************************************************/ + sys::Uint32_T getNextOffset() const + { + return mNextOffset; + } + +private: + + /** + ***************************************************************** + * Reads the specified number of elements into the specified + * buffer, in TIFF stripped format. Converts the TIFF image from + * the TIFF stripped format into raster format. + * @param buffer + * the buffer to populate with image data + * @param numElementsToRead + * the number of elements (not bytes) to read from the image + *****************************************************************/ + void getStripData(unsigned char *buffer, sys::Uint32_T numElementsToRead); + + /** + ***************************************************************** + * Reads the specified number of elements into the specified + * buffer, in TIFF tiled format. Converts the TIFF image from + * the TIFF tiled format into raster format. + * @param buffer + * the buffer to populate with image data + * @param numElementsToRead + * the number of elements (not bytes) to read from the image + *****************************************************************/ + void getTileData(unsigned char *buffer, sys::Uint32_T numElementsToRead); + + //! Contains the IFD for this image. + tiff::IFD mIFD; + + //! A pointer to the "StripByteCounts" IFDEntry to make reading faster. + tiff::IFDEntry *mStripByteCounts; + + //! A pointer to the "StripOffsets" IFDEntry to make reading faster. + tiff::IFDEntry *mStripOffsets; + + //! Points to the input file stream. + io::FileInputStream *mInput; + + //! The offset to the next IFD. + sys::Uint32_T mNextOffset; + + //! Used to keep track of the current read position in the file. + sys::Uint32_T mBytePosition; + + sys::Uint32_T mStripIndex; + + //! The element size of the image. + unsigned short mElementSize; + + //! Whether to reverse bytes when reading. + bool mReverseBytes; +}; + +} // End namespace. + +#endif // __TIFF_IMAGE_READER_H__ diff --git a/modules/c++/tiff/include/tiff/ImageWriter.h b/modules/c++/tiff/include/tiff/ImageWriter.h new file mode 100644 index 000000000..c3feb0d16 --- /dev/null +++ b/modules/c++/tiff/include/tiff/ImageWriter.h @@ -0,0 +1,258 @@ +/* ========================================================================= + * This file is part of tiff-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2011, General Dynamics - Advanced Information Systems + * + * tiff-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __TIFF_IMAGE_WRITER_H__ +#define __TIFF_IMAGE_WRITER_H__ + +#include + +#include "tiff/Common.h" +#include "tiff/IFDEntry.h" +#include "tiff/IFD.h" + +namespace tiff +{ + +/** + ********************************************************************* + * @class ImageWriter + * @brief Writes a TIFF image + * + * Writes a TIFF image to a stream. Contains functions for writing + * the image's IFD, and for putting data to a stream. + *********************************************************************/ +class ImageWriter +{ +public: + //! The ideal tile size if a tiled file. + static const unsigned short CHUNK_SIZE; + + //! The format of the image, either STRIPPED or TILED. + enum ImageFormat { STRIPPED, TILED }; + + /** + ***************************************************************** + * Constructor. Initializes the object with a pointer to the + * output stream, and a file offset that indicates where the + * beginning of the image is in the file (since TIFF can have + * more than one image in a file). + * + * @param output + * the output stream to write the image to + * @param ifdOffset + * the offset to the beginning of the IFD for this image + *****************************************************************/ + ImageWriter(io::FileOutputStream *output, const sys::Uint32_T ifdOffset) : + mStripByteCounts(NULL), + mTileOffsets(NULL), + mOutput(output), mIFDOffset(ifdOffset), + mIdealChunkSize(CHUNK_SIZE), mBytePosition(0), mElementSize(0), + mValidated(false), mFormat(STRIPPED) + { + } + + //! Destructor + ~ImageWriter() + { + } + + /** + ***************************************************************** + * Writes data from the specified buffer into the stream. The + * data in the buffer must be in raster format. + * + * @param buffer + * the data to write to the output stream + * @param numElementsToWrite + * the number of elements (not bytes) to write to the stream + *****************************************************************/ + void putData(const unsigned char *buffer, + sys::Uint32_T numElementsToWrite); + + /** + ***************************************************************** + * Returns a pointer to this image's IFD. Allows the user to set + * information in this image's IFD externally. + * + * @return + * a pointer to this image's IFD + *****************************************************************/ + tiff::IFD *getIFD() + { + return &mIFD; + } + + //! Writes this image's IFD to the output stream. + void writeIFD(); + + /** + ***************************************************************** + * Returns the position to write the next IFD offset to. When + * the IFD for this image is written out, the next IFD offset is + * default to 0 (indicating there is no next image in the file). + * If there is to be more than one image in the file, you have to + * have a way of knowing where to write the offset to the next + * image's IFD. This returns the position where the next IFD + * offset must be written. + * + * @return + * the position to write the next IFD offset to + *****************************************************************/ + sys::Uint32_T getNextIFDOffset() const + { + return mIFDOffset; + } + + /** + ***************************************************************** + * Sets the ideal tile size. Used if the image is a tiled image. + * Indicates an ideal size to allocate for one tile. The actual + * tile size may not be exactly this number because there are + * certain rules that must be followed for tile sizes, but it will + * get as close to this number as it possibly can. + * + * @param size + * the ideal tile size to allocate if this is a tiled image + *****************************************************************/ + void setIdealChunkSize(const sys::Uint32_T size) + { + mIdealChunkSize = size; + } + + /** + ***************************************************************** + * Sets the image format to either TILED or STRIPPED. The + * default is STRIPPED. + * + * @param format + * the format to use for this image, either TILED or STRIPPED + *****************************************************************/ + void setImageFormat(const ImageFormat format) + { + mFormat = format; + } + + /** + ***************************************************************** + * Retrieves the current image format for the image. + * + * @return + * the image format of this image, either TILED or STRIPPED + *****************************************************************/ + ImageFormat getImageFormat() + { + return mFormat; + } + + + /** + ***************************************************************** + * Makes sure that all necessary TIFF tags (IFD entries) are + * defined in the IFD before allowing the image to be written. + * For some tags, there are reasonable defaults that this + * function will set, others must be set by the user and this + * function will throw an exception indicating the missing tag. + *****************************************************************/ + void validate(); + +private: + /** + ***************************************************************** + * Adds IFD entries to the IFD that indicate that the image + * should be written in a stripped format. + *****************************************************************/ + void initStrips(); + + /** + ***************************************************************** + * Adds IFD entries to the IFD that indicate that the image + * should be written in a tiled format. + *****************************************************************/ + void initTiles(); + + /** + ***************************************************************** + * Writes data to a file in stripped format. + * + * @param buffer + * the buffer to write to the file + * @param numElementsToWrite + * the number of elements (not bytes) to write to the file + *****************************************************************/ + void putStripData(const unsigned char *buffer, + sys::Uint32_T numElementsToWrite); + + /** + ***************************************************************** + * Writes data to a file in tiled format. + * + * @param buffer + * the buffer to write to the file + * @param numElementsToWrite + * the number of elements (not bytes) to write to the file + *****************************************************************/ + void putTileData(const unsigned char *buffer, + sys::Uint32_T numElementsToWrite); + + //! The TIFF IFD for this image + tiff::IFD mIFD; + + //! A pointer to the StripByteCounts entry, prevents frequent IFD access + tiff::IFDEntry *mStripByteCounts; + + //! A pointer to the TileOffsets entry, prevents frequent IFD access + tiff::IFDEntry *mTileOffsets; + + //! A pointer to the TileWidth entry, prevents frequent IFD access + tiff::IFDEntry *mTileWidth; + + //! A pointer to the TileLength entry, prevents frequent IFD access + tiff::IFDEntry *mTileLength; + + //! A pointer to the TileByteCounts entry, prevents frequent IFD access + tiff::IFDEntry *mTileByteCounts; + + //! A pointer to the output stream + io::FileOutputStream *mOutput; + + //! The position to write the next IFD to + sys::Uint32_T mIFDOffset; + + //! The ideal size of a tile + sys::Uint32_T mIdealChunkSize; + + //! Used to determine the position in the image + sys::Uint32_T mBytePosition; + + //! The image's element size. Stored here to prevent frequent IFD access + unsigned short mElementSize; + + //! Indicates whether or not the IFD has been validated already + bool mValidated; + + //! The format of the file, either TILED or STRIPPED + ImageFormat mFormat; +}; + +} // End namespace. + +#endif // __TIFF_IMAGE_WRITER_H__ diff --git a/modules/c++/tiff/include/tiff/KnownTags.h b/modules/c++/tiff/include/tiff/KnownTags.h new file mode 100644 index 000000000..4255b06f6 --- /dev/null +++ b/modules/c++/tiff/include/tiff/KnownTags.h @@ -0,0 +1,125 @@ +/* ========================================================================= + * This file is part of tiff-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2011, General Dynamics - Advanced Information Systems + * + * tiff-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __TIFF_KNOWN_TAGS_H__ +#define __TIFF_KNOWN_TAGS_H__ + +#include +#include +#include + +#include "tiff/IFDEntry.h" + +namespace tiff +{ + +/** + * This class is a container for known TIFF tags. + */ +class KnownTags +{ +public: + + KnownTags(); + + //! Destructor + ~KnownTags(); + + /** + ***************************************************************** + * Returns the IFDEntry associated with the specified + * string. + * + * @param nameKey + * the key to look up in the map, based on the name of the + * IFDEntry (i.e. "ImageWidth") + * @return + * the IFDEntry associated with the name + *****************************************************************/ + tiff::IFDEntry *operator[](const std::string& nameKey); + + /** + ***************************************************************** + * Returns the IFDEntry associated with the specified + * short. + * + * @param nameKey + * the key to look up in the map, based on the TIFF tag + * identifier of the IFDEntry (i.e. 256) + * @return + * the IFDEntry associated with the identifier + *****************************************************************/ + tiff::IFDEntry *operator[](const unsigned short tagKey); + + //! Some common tags + static const char IMAGE_WIDTH[]; + static const char IMAGE_LENGTH[]; + static const char BITS_PER_SAMPLE[]; + static const char COMPRESSION[]; + static const char SAMPLES_PER_PIXEL[]; + static const char PHOTOMETRIC_INTERPRETATION[]; + static const char SAMPLE_FORMAT[]; + + + /** + ***************************************************************** + * Adds a IFDEntry with the specified values to the + * KnownTagsRegsitry. + * + * @param tag + * the TIFF tag identifier to add as (i.e. 256) + * @param type + * the TIFF type of the IFDEntry + * @param name + * the name identifier to add as (i.e. "ImageWidth") + *****************************************************************/ + void addEntry(const unsigned short tag, const unsigned short type, + const std::string& name); + +private: + + //! The name to tag identifier map + std::map mNameMap; + + //! The tag identifier to IFDEntry map + std::map mKnownTags; +}; + +/** + ********************************************************************* + * @class KnownTagsRegistry + * @brief Contains a globally accessable listing of all possible IFD + * entries supported in the TIFF 6.0 specification. + * + * This class contains all TIFF IFD entries that are in the TIFF 6.0 + * specification. This includes the TIFF type of each tag as well + * as a string that names the tag (i.e. "ImageWidth"). The entries + * are globally allocated the first time the KnownTagsRegistry is + * instantiated. There are only two functions defined, both are + * the [] operator, both return the TIFFIFDEntry associated with the + * specified input. + *********************************************************************/ +typedef mt::Singleton KnownTagsRegistry; + +} // End namespace. + +#endif // __TIFF_TAG_MAP_REGISTRY_H__ diff --git a/modules/c++/tiff/include/tiff/TypeFactory.h b/modules/c++/tiff/include/tiff/TypeFactory.h new file mode 100644 index 000000000..5fe04c26c --- /dev/null +++ b/modules/c++/tiff/include/tiff/TypeFactory.h @@ -0,0 +1,73 @@ +/* ========================================================================= + * This file is part of tiff-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2011, General Dynamics - Advanced Information Systems + * + * tiff-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __TIFF_TYPE_FACTORY_H__ +#define __TIFF_TYPE_FACTORY_H__ + +#include "tiff/GenericType.h" + +namespace tiff +{ + +/** + ********************************************************************* + * @class TypeFactory + * @brief A factory for creating tiff::GenericTypes + * + * Contains a static member function that creates an tiff::GenericType, + * inserting the provided data as the specified type. The types + * assume a specific size for the data, see tiff::Const for the size + * of each TIFF type. + *********************************************************************/ +class TypeFactory +{ +public: + //! Default constructor + TypeFactory() + { + } + + //! Deconstructor + ~TypeFactory() + { + } + + /** + ***************************************************************** + * Creates a tiff::GenericType, inserting the provided data as the + * specified type. The types assume a specific size for the data, + * see tiff::Const for the size of each TIFF type. + * + * @param data + * the data to insert into the tiff::GenericType + * @param type + * the tiff::GenericType to create, see tiff::Const::Type + * @return + * a pointer to a TypeInterface + *****************************************************************/ + static tiff::TypeInterface *create(const unsigned char *data, + const unsigned short type); +}; + +} // End namespace. + +#endif // __TIFF_TYPE_FACTORY_H__ diff --git a/modules/c++/tiff/include/tiff/Utils.h b/modules/c++/tiff/include/tiff/Utils.h new file mode 100644 index 000000000..30b1f6166 --- /dev/null +++ b/modules/c++/tiff/include/tiff/Utils.h @@ -0,0 +1,46 @@ +/* ========================================================================= + * This file is part of tiff-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2011, General Dynamics - Advanced Information Systems + * + * tiff-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __TIFF_UTILS_H__ +#define __TIFF_UTILS_H__ + +#include "tiff/IFD.h" + +namespace tiff +{ + +class Utils +{ +public: + + static bool hasGeoTiffIFD(tiff::IFD* inputIFD); + static tiff::IFD* createGeoTiffIFD(tiff::IFD* inputIFD); + +private: + Utils() + { + } + +}; + +} +#endif // __TIFF_UTILS_H__ diff --git a/modules/c++/tiff/source/Common.cpp b/modules/c++/tiff/source/Common.cpp new file mode 100644 index 000000000..ce5f8a0d7 --- /dev/null +++ b/modules/c++/tiff/source/Common.cpp @@ -0,0 +1,60 @@ +/* ========================================================================= + * This file is part of tiff-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2011, General Dynamics - Advanced Information Systems + * + * tiff-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include "tiff/Common.h" + +#include +#include + +//! Initialize the byte count values for each TIFF type. +short tiff::Const::mTypeSizes[tiff::Const::Type::MAX] = +{ 0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8 }; + +std::string tiff::RationalPrintStrategy::toString(const sys::Uint32_T data) +{ + std::ostringstream tempStream; + sys::Uint32_T numerator = *((sys::Uint32_T *)(&data)); + sys::Uint32_T denominator = *((sys::Uint32_T *)(&data + sizeof(sys::Uint32_T))); + tempStream << numerator << "/" << denominator; + + return tempStream.str(); +} + +sys::Uint64_T tiff::combine(sys::Uint32_T numerator, + sys::Uint32_T denominator) +{ + sys::Uint64_T value; + sys::Uint32_T *ptr = (sys::Uint32_T *)&value; + + memcpy(ptr, &numerator, sizeof(sys::Uint32_T)); + ptr++; + memcpy(ptr, &denominator, sizeof(sys::Uint32_T)); + + return value; +} +void tiff::split(sys::Uint64_T value, sys::Uint32_T &numerator, + sys::Uint32_T &denominator) +{ + numerator = ((sys::Uint32_T *)&value)[0]; + denominator = ((sys::Uint32_T *)&value)[1]; +} + diff --git a/modules/c++/tiff/source/FileReader.cpp b/modules/c++/tiff/source/FileReader.cpp new file mode 100644 index 000000000..402db649a --- /dev/null +++ b/modules/c++/tiff/source/FileReader.cpp @@ -0,0 +1,114 @@ +/* ========================================================================= + * This file is part of tiff-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2011, General Dynamics - Advanced Information Systems + * + * tiff-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ +#include "tiff/FileReader.h" + +#include +#include +#include +#include +#include + +#include "tiff/ImageReader.h" +#include "tiff/IFD.h" + + +void tiff::FileReader::openFile(const std::string& fileName) +{ + if (mInput.isOpen()) + throw except::Exception(Ctxt("Last file not closed; call close() first.")); + + if (fileName == "-") + throw except::Exception(Ctxt("Cannot read TIFF from std::cin")); + + if (fileName == "") + throw except::Exception(Ctxt("No file name provided")); + + mInput.create(fileName.c_str()); + if (!mInput.isOpen()) + throw except::Exception(Ctxt("File was not opened")); + + // Read TIFF header from input + mHeader.deserialize(mInput); + + mReverseBytes = mHeader.isDifferentByteOrdering(); + sys::Uint32_T offset = mHeader.getIFDOffset(); + while (offset != 0) + { + tiff::ImageReader *imageReader = new tiff::ImageReader(&mInput); + + mInput.seek(offset, io::Seekable::START); + imageReader->process(mReverseBytes); + mImages.push_back(imageReader); + + offset = imageReader->getNextOffset(); + } +} + +void tiff::FileReader::close() +{ + memset(&mHeader, 0, sizeof(mHeader)); + + mInput.close(); + + std::vector::iterator readIter; + for (readIter = mImages.begin(); readIter != mImages.end(); ++readIter) + delete *readIter; + + mImages.clear(); +} + +tiff::ImageReader *tiff::FileReader::operator[](const sys::Uint32_T index) const +{ + if (index >= mImages.size()) + throw except::Exception(Ctxt(FmtX("Index out of range: %d", index))); + + return mImages[index]; +} + +void tiff::FileReader::print(io::OutputStream &output) const +{ + // Print the header information + mHeader.print(output); + output.writeln(""); + + // Print each subfile's information (each subfile has it's own IFD). + for (sys::Uint32_T i = 0; i < mImages.size(); ++i) + { + std::ostringstream message; + message << "Sub-File: " << i + 1 << std::endl; + output.write(message.str()); + + mImages[i]->print(output); + output.writeln(""); + } +} + +void tiff::FileReader::getData(unsigned char *buffer, + const sys::Uint32_T numElementsToRead, const sys::Uint32_T imageIndex) +{ + if (imageIndex >= mImages.size()) + throw except::Exception(Ctxt(FmtX("Index out of range", imageIndex))); + + mImages[imageIndex]->getData(buffer, numElementsToRead); +} + + diff --git a/modules/c++/tiff/source/FileWriter.cpp b/modules/c++/tiff/source/FileWriter.cpp new file mode 100644 index 000000000..c2d6f1386 --- /dev/null +++ b/modules/c++/tiff/source/FileWriter.cpp @@ -0,0 +1,112 @@ +/* ========================================================================= + * This file is part of tiff-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2011, General Dynamics - Advanced Information Systems + * + * tiff-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ +#include +#include +#include "tiff/ImageWriter.h" +#include "tiff/FileWriter.h" + +tiff::FileWriter::~FileWriter() +{ + for (size_t ii = 0; ii < mImages.size(); ++ii) + { + delete mImages[ii]; + } + + try + { + if (mOutput.isOpen()) + { + mOutput.close(); + } + } + catch (...) + { + } +} + +void tiff::FileWriter::openFile(const std::string& fileName) +{ + if (mOutput.isOpen()) + throw except::Exception(Ctxt("Last file not closed; call close() first.")); + + if (fileName == "-") + throw except::Exception(Ctxt("Cannot write TIFF to std::cout")); + + if (fileName == "") + throw except::Exception(Ctxt("No filename provided")); + + mOutput.create(fileName.c_str()); +} + +void tiff::FileWriter::close() +{ + mIFDOffset = 0; + memset(&mHeader, 0, sizeof(mHeader)); + + mOutput.close(); + + for (size_t ii = 0; ii < mImages.size(); ++ii) + { + delete mImages[ii]; + } + mImages.clear(); +} + +tiff::ImageWriter * tiff::FileWriter::operator[](const sys::Uint32_T index) const +{ + if (index >= mImages.size()) + throw except::Exception(Ctxt("Invalid sub-image index")); + + return mImages[index]; +} + +void tiff::FileWriter::putData(const unsigned char *buffer, + sys::Uint32_T numElementsToWrite, + sys::Uint32_T index) +{ + if (index >= mImages.size()) + throw except::Exception(Ctxt("Invalid sub-image index")); + + mImages[index]->putData(buffer, numElementsToWrite); +} + +tiff::ImageWriter *tiff::FileWriter::addImage() +{ + if (!mImages.empty()) + mIFDOffset = mImages.back()->getNextIFDOffset(); + + std::auto_ptr + image(new tiff::ImageWriter(&mOutput, mIFDOffset)); + mImages.push_back(image.get()); + tiff::ImageWriter* const writer = image.release(); + + return writer; +} + +void tiff::FileWriter::writeHeader() +{ + mHeader.serialize(mOutput); + + // Have to rewind a few bytes to write out the actual IFD offset. + mIFDOffset = mOutput.tell(); + mIFDOffset -= (int)sizeof(sys::Uint32_T); +} diff --git a/modules/c++/tiff/source/Header.cpp b/modules/c++/tiff/source/Header.cpp new file mode 100644 index 000000000..f00de7ef1 --- /dev/null +++ b/modules/c++/tiff/source/Header.cpp @@ -0,0 +1,60 @@ +/* ========================================================================= + * This file is part of tiff-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2011, General Dynamics - Advanced Information Systems + * + * tiff-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include "tiff/Header.h" +#include +#include + +// INCOMPLETE +void tiff::Header::serialize(io::OutputStream& output) +{ + output.write((sys::byte *)&mByteOrder, sizeof(mByteOrder)); + output.write((sys::byte *)&mId, sizeof(mId)); + output.write((sys::byte *)&mIFDOffset, sizeof(mIFDOffset)); +} + +void tiff::Header::deserialize(io::InputStream& input) +{ + input.read((sys::byte *)&mByteOrder, sizeof(mByteOrder)); + input.read((sys::byte *)&mId, sizeof(mId)); + input.read((sys::byte *)&mIFDOffset, sizeof(mIFDOffset)); + + mDifferentByteOrdering = sys::isBigEndianSystem() ? \ + getByteOrder() != tiff::Header::MM : getByteOrder() != tiff::Header::II; + + if (mDifferentByteOrdering) + { + mId = sys::byteSwap(mId); + mIFDOffset = sys::byteSwap(mIFDOffset); + } +} + +void tiff::Header::print(io::OutputStream& output) const +{ + std::ostringstream message; + message << "Type: " << mByteOrder[0] << mByteOrder[1] << std::endl; + message << "Version: " << mId << std::endl; + message << "IFD Offset: " << mIFDOffset << std::endl; + output.write(message.str()); +} + + diff --git a/modules/c++/tiff/source/IFD.cpp b/modules/c++/tiff/source/IFD.cpp new file mode 100644 index 000000000..07c670781 --- /dev/null +++ b/modules/c++/tiff/source/IFD.cpp @@ -0,0 +1,231 @@ +/* ========================================================================= + * This file is part of tiff-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2011, General Dynamics - Advanced Information Systems + * + * tiff-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + + +#include "tiff/IFD.h" +#include "tiff/Common.h" +#include "tiff/GenericType.h" +#include "tiff/IFDEntry.h" +#include "tiff/KnownTags.h" + +#include +#include +#include +#include + +tiff::IFDEntry *tiff::IFD::operator[](const char *name) +{ + tiff::IFDEntry *mapEntry = tiff::KnownTagsRegistry::getInstance()[name]; + if (!mapEntry) return NULL; + return (*this)[mapEntry->getTagID()]; +} + +tiff::IFDEntry *tiff::IFD::operator[](unsigned short tag) +{ + // Ensures that the key exists. Without this check, the defined + // behavior for the [] operator is to create an entry if it does + // not exist. This is to make sure that the map doesn't get full + // of invalid key/value pairs if you're just trying to verify whether + // a key already exists of not. + return exists(tag) ? mIFD[tag] : NULL; +} + +bool tiff::IFD::exists(unsigned short tag) +{ + return mIFD.find(tag) != mIFD.end(); +} + +bool tiff::IFD::exists(const char *name) +{ + tiff::IFDEntry *mapEntry = tiff::KnownTagsRegistry::getInstance()[name]; + if (!mapEntry) + return false; + return exists(mapEntry->getTagID()); +} + +void tiff::IFD::addEntry(const tiff::IFDEntry *entry) +{ + unsigned short id = entry->getTagID(); + mIFD[id] = new tiff::IFDEntry; + *(mIFD[id]) = *entry; +} + +void tiff::IFD::addEntry(const std::string& name) +{ + tiff::IFDEntry *mapEntry = tiff::KnownTagsRegistry::getInstance()[name]; + // we can't add it b/c we don't know about this tag + if (!mapEntry) + throw except::Exception(Ctxt(FmtX( + "Unable to add IFD Entry: unknown tag [%s]", name.c_str()))); + + unsigned short id = mapEntry->getTagID(); + + mIFD[id] = new tiff::IFDEntry; + *(mIFD[id]) = *mapEntry; +} + +void tiff::IFD::deserialize(io::InputStream& input) +{ + deserialize(input, false); +} + +void tiff::IFD::deserialize(io::InputStream& input, const bool reverseBytes) +{ + unsigned short ifdEntryCount; + input.read((sys::byte *)&ifdEntryCount, sizeof(ifdEntryCount)); + if (reverseBytes) + ifdEntryCount = sys::byteSwap(ifdEntryCount); + + for (unsigned short i = 0; i < ifdEntryCount; i++) + { + tiff::IFDEntry *entry = new tiff::IFDEntry(); + entry->deserialize(input, reverseBytes); + mIFD[entry->getTagID()] = entry; + } +} + +void tiff::IFD::serialize(io::OutputStream& output) +{ + io::Seekable *seekable = + dynamic_cast(&output); + if (seekable == NULL) + throw except::Exception(Ctxt("Can only serialize IFD to seekable stream")); + + // Makes sure all data offsets are defined for each entry. + // Keep the offset just past the end of the IFD. This offset + // is where the next potential image could be written. + sys::Uint32_T endOffset = finalize(seekable->tell()); + + // Write out IFD entry count. + unsigned short ifdEntryCount = mIFD.size(); + output.write((sys::byte *)&ifdEntryCount, sizeof(ifdEntryCount)); + + // Write out each IFD entry. + for (IFDType::const_iterator i = mIFD.begin(); i != mIFD.end(); ++i) + { + tiff::IFDEntry *entry = i->second; + entry->serialize(output); + } + + // Remember the current position in case there is another IFD after + // this one. + mNextIFDOffsetPosition = seekable->tell(); + + // Write out the default next IFD location. + sys::Uint32_T nextOffset = 0; + output.write((sys::byte *)&nextOffset, sizeof(sys::Uint32_T)); + + // Seek the end of the IFD, the next image can begin here. + seekable->seek(endOffset, io::Seekable::START); +} + +void tiff::IFD::print(io::OutputStream& output) const +{ + sys::Uint32_T x = 1; + + for (IFDType::const_iterator i = mIFD.begin(); i != mIFD.end(); ++i, ++x) + { + std::ostringstream message; + message << "Entry Number: " << x << std::endl; + output.write(message.str()); + + i->second->print(output); + output.writeln(""); + } +} + +sys::Uint32_T tiff::IFD::getImageWidth() +{ + tiff::IFDEntry *imageWidth = (*this)[tiff::KnownTags::IMAGE_WIDTH]; + if (!imageWidth) + return 0; + + if (imageWidth->getType() == tiff::Const::Type::LONG) + return *(tiff::GenericType *)(*imageWidth)[0]; + + return *(tiff::GenericType *)(*imageWidth)[0]; +} + +sys::Uint32_T tiff::IFD::getImageLength() +{ + tiff::IFDEntry *imageLength = (*this)[tiff::KnownTags::IMAGE_LENGTH]; + if (!imageLength) + return 0; + + if (imageLength->getType() == tiff::Const::Type::LONG) + return *(tiff::GenericType *)(*imageLength)[0]; + + return *(tiff::GenericType *)(*imageLength)[0]; +} + +sys::Uint32_T tiff::IFD::getImageSize() +{ + sys::Uint32_T width = getImageWidth(); + sys::Uint32_T length = getImageLength(); + unsigned short elementSize = getElementSize(); + + return width * length * elementSize; +} + +unsigned short tiff::IFD::getNumBands() +{ + unsigned short numBands = 1; + + tiff::IFDEntry *samplesPerPixel = (*this)[tiff::KnownTags::SAMPLES_PER_PIXEL]; + tiff::IFDEntry *bitsPerSample = (*this)[tiff::KnownTags::BITS_PER_SAMPLE]; + + if (samplesPerPixel) + numBands = *(::tiff::GenericType *)(*samplesPerPixel)[0]; + else if (bitsPerSample) + numBands = bitsPerSample->getCount(); + + return numBands; +} + +unsigned short tiff::IFD::getElementSize() +{ + tiff::IFDEntry *bitsPerSample = (*this)[tiff::KnownTags::BITS_PER_SAMPLE]; + unsigned short bytesPerSample = (!bitsPerSample) ? 1 + : *(tiff::GenericType *)(*bitsPerSample)[0] >> 3; + + return bytesPerSample * getNumBands(); +} + +sys::Uint32_T tiff::IFD::finalize(const sys::Uint32_T offset) +{ + // Find the beginning offset to extra IFD data. The IFD length is + // the size of an IFD entry multiplied by the number of entries, plus + // 4 bytes to hold the offset to the next IFD, and 2 bytes to hold the + // IFD entry count. + sys::Uint32_T dataOffset = offset + sizeof(short) + (mIFD.size() + * tiff::IFDEntry::sizeOf()) + sizeof(sys::Uint32_T); + + for (IFDType::iterator i = mIFD.begin(); i != mIFD.end(); ++i) + { + // Send in the current offset. If the value size of the IFD entry + // requires that data be placed outside the IFD entry, the offset that + // is returned will be adjusted to compensate for that data. + dataOffset = i->second->finalize(dataOffset); + } + + return dataOffset; +} diff --git a/modules/c++/tiff/source/IFDEntry.cpp b/modules/c++/tiff/source/IFDEntry.cpp new file mode 100644 index 000000000..9fda7f08c --- /dev/null +++ b/modules/c++/tiff/source/IFDEntry.cpp @@ -0,0 +1,234 @@ +/* ========================================================================= + * This file is part of tiff-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2011, General Dynamics - Advanced Information Systems + * + * tiff-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include +#include +#include +#include +#include + +#include "tiff/Common.h" +#include "tiff/GenericType.h" +#include "tiff/KnownTags.h" +#include "tiff/TypeFactory.h" +#include "tiff/IFDEntry.h" + + +void tiff::IFDEntry::serialize(io::OutputStream& output) +{ + io::Seekable *seekable = + dynamic_cast(&output); + if (seekable == NULL) + throw except::Exception(Ctxt("Can only serialize IFDEntry to seekable stream")); + + output.write((sys::byte *)&mTag, sizeof(mTag)); + output.write((sys::byte *)&mType, sizeof(mType)); + output.write((sys::byte *)&mCount, sizeof(mCount)); + + sys::Uint32_T size = mCount * tiff::Const::sizeOf(mType); + + if (size > 4) + { + // Keep the current position and jump to the write position. + sys::Uint32_T current = seekable->tell(); + seekable->seek(mOffset, io::Seekable::START); + + // Write the values out at the current cursor position + for (sys::Uint32_T i = 0; i < mValues.size(); ++i) + output.write((sys::byte *)mValues[i]->data(), + mValues[i]->size()); + + // Reset the cursor + seekable->seek(current, io::Seekable::START); + + // Write out the data offset. + output.write((sys::byte *)&mOffset, sizeof(mOffset)); + } + else + { + for (sys::Uint32_T i = 0; i < mCount; ++i) + { + // The value must take up four bytes. If the number of bytes is + // less than four, duplicate the value until you hit 4 bytes in length. + unsigned short iterations = (4 / mCount) / mValues[i]->size(); + + for (int j = 0; j < iterations; ++j) + output.write((sys::byte *)mValues[i]->data(), + mValues[i]->size()); + } + } +} + +void tiff::IFDEntry::deserialize(io::InputStream& input) +{ + deserialize(input, false); +} + +void tiff::IFDEntry::deserialize(io::InputStream& input, const bool reverseBytes) +{ + io::Seekable *seekable = + dynamic_cast(&input); + if (seekable == NULL) + throw except::Exception(Ctxt("Can only deserialize IFDEntry from seekable stream")); + + input.read((char *)&mTag, sizeof(mTag)); + input.read((char *)&mType, sizeof(mType)); + input.read((char *)&mCount, sizeof(mCount)); + input.read((char *)&mOffset, sizeof(mOffset)); + + if (reverseBytes) + { + mTag = sys::byteSwap(mTag); + mType = sys::byteSwap(mType); + mCount = sys::byteSwap(mCount); + mOffset = sys::byteSwap(mOffset); + } + + sys::Uint32_T size = mCount * tiff::Const::sizeOf(mType); + + if (size > 4) + { + // Keep the current position and jump to the read position. + sys::Uint32_T current = seekable->tell(); + seekable->seek(mOffset, io::Seekable::START); + + // Read in the value(s); + sys::byte *buffer = new sys::byte[size]; + + input.read(buffer, size); + if (reverseBytes) + { + sys::Uint32_T elementSize = tiff::Const::sizeOf(mType); + sys::Uint32_T numElements = mCount; + if (mType == tiff::Const::Type::RATIONAL && mType + == tiff::Const::Type::SRATIONAL) + { + elementSize = tiff::Const::sizeOf(mType) / 2; + numElements = mCount * 2; + } + if (elementSize > 1) + sys::byteSwap(buffer, elementSize, numElements); + } + + parseValues((const unsigned char *)buffer); + delete[] buffer; + + // Reset the cursor position. + seekable->seek(current, io::Seekable::START); + } + else + { + if (reverseBytes) + { + // Re-reverse because a value may be less than 4 bytes. + mOffset = sys::byteSwap(mOffset); + unsigned short elementSize = tiff::Const::sizeOf(mType); + sys::byteSwap((sys::byte*)&mOffset, elementSize, sizeof(mOffset) + / elementSize); + } + parseValues((unsigned char *)&mOffset); + } + + //try to retrieve the name as well + tiff::IFDEntry *mapEntry = tiff::KnownTagsRegistry::getInstance()[mTag]; + mName = mapEntry ? mapEntry->getName() : ""; +} + +void tiff::IFDEntry::print(io::OutputStream& output) const +{ + std::ostringstream message; + message << "Tag: " << mTag << " (\"" << mName << "\")" + << std::endl; + message << "Element Type: " << mType << std::endl; + message << "Number of Elements: " << mCount << std::endl; + + // Print the offset if one exists + if (mCount * tiff::Const::sizeOf(mType) > 4) + message << "Offset: " << mOffset << std::endl; + + message << "Value(s): "; + for (sys::Uint32_T i = 0; i < mCount; ++i) + { + message << mValues[i]->toString(); + if (mType != tiff::Const::Type::ASCII) + message << " "; + } + message << std::endl; + + output.write(message.str()); +} + +void tiff::IFDEntry::parseValues(const unsigned char *buffer, + const sys::Uint32_T count) +{ + mCount = count; + parseValues(buffer); +} + +void tiff::IFDEntry::addValue(double value) +{ + const unsigned char* const valuePtr = + reinterpret_cast(&value); + + addValue(tiff::TypeFactory::create(valuePtr, + tiff::Const::Type::DOUBLE)); +} + +void tiff::IFDEntry::addValues(const char* str, int tiffType) +{ + const unsigned char* const strPtr = + reinterpret_cast(str); + + for (size_t ii = 0, len = ::strlen(str) + 1; ii < len; ++ii) + { + std::auto_ptr + value(tiff::TypeFactory::create(strPtr + ii, tiffType)); + addValue(value); + } +} + +void tiff::IFDEntry::parseValues(const unsigned char *buffer) +{ + unsigned char *marker = (unsigned char *)buffer; + for (sys::Uint32_T i = 0; i < mCount; i++) + { + tiff::TypeInterface *nextValue = tiff::TypeFactory::create(marker, + mType); + mValues.push_back(nextValue); + unsigned short size = nextValue->size(); + marker = marker + size; + } +} + +sys::Uint32_T tiff::IFDEntry::finalize(const sys::Uint32_T offset) +{ + mCount = mValues.size(); + + sys::Uint32_T size = mCount * tiff::Const::sizeOf(mType); + if (size > 4) + { + mOffset = offset; + return offset + size; + } + + return offset; +} diff --git a/modules/c++/tiff/source/ImageReader.cpp b/modules/c++/tiff/source/ImageReader.cpp new file mode 100644 index 000000000..20ad5beea --- /dev/null +++ b/modules/c++/tiff/source/ImageReader.cpp @@ -0,0 +1,215 @@ +/* ========================================================================= + * This file is part of tiff-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2011, General Dynamics - Advanced Information Systems + * + * tiff-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include "tiff/ImageReader.h" + +#include +#include +#include +#include "tiff/Common.h" +#include "tiff/GenericType.h" +#include "tiff/IFDEntry.h" + +void tiff::ImageReader::process(const bool reverseBytes) +{ + mReverseBytes = reverseBytes; + + mIFD.deserialize(*mInput, mReverseBytes); + + mInput->read((sys::byte *)&mNextOffset, sizeof(mNextOffset)); + if (mReverseBytes) + mNextOffset = sys::byteSwap(mNextOffset); + + // Done here to lower the number of calls to it later. + mElementSize = mIFD.getElementSize(); + + mStripByteCounts = mIFD["StripByteCounts"]; + mStripOffsets = mIFD["StripOffsets"]; +} + +void tiff::ImageReader::print(io::OutputStream &output) const +{ + mIFD.print(output); + output.writeln(""); + + std::ostringstream message; + message << "Next IFD Offset: " << mNextOffset << std::endl; + output.write(message.str()); +} + +void tiff::ImageReader::getData(unsigned char *buffer, + const sys::Uint32_T numElementsToRead) +{ + //see if it is uncompressed + tiff::IFDEntry *compression = mIFD["Compression"]; + if (compression) + { + unsigned short c = *(tiff::GenericType *)(*compression)[0]; + if (c != tiff::Const::CompressionType::NO_COMPRESSION) + throw except::Exception(Ctxt(FmtX("Unsupported compression type: %d", c))); + } + + if (mIFD["StripOffsets"]) + getStripData(buffer, numElementsToRead); + else if (mIFD["TileOffsets"]) + getTileData(buffer, numElementsToRead); + else + throw except::Exception(Ctxt("Unsupported TIFF file format")); + + if (mReverseBytes) + sys::byteSwap((sys::byte*)buffer, mElementSize, numElementsToRead); +} + +void tiff::ImageReader::getStripData(unsigned char *buffer, + sys::Uint32_T numElementsToRead) +{ + sys::Uint32_T bufferOffset = 0; + + //figure out how far we are in the current strip + sys::Uint32_T stripOffset = 0; + for (size_t i = 0; i < mStripIndex; ++i) + stripOffset += *(tiff::GenericType *)(*mStripByteCounts)[i]; + sys::Uint32_T stripPosition = mBytePosition - stripOffset; + + //how many bytes do we need to read? + sys::Uint32_T numBytesToRead = numElementsToRead * mElementSize; + + while (numBytesToRead) + { + if (mStripIndex >= mStripOffsets->getCount()) + throw except::Exception(Ctxt("Invalid strip offset index")); + + sys::Uint32_T stripSize = *(tiff::GenericType *)(*mStripByteCounts)[mStripIndex]; + + // Calculate what remains to be read in the current strip. + sys::Uint32_T remainingBytesInStrip = stripSize - stripPosition; + + // Seek to the strip offset plus the last read position. + sys::Uint32_T seekPos = (*(tiff::GenericType *)(*mStripOffsets)[mStripIndex]) + stripPosition; + + + sys::Uint32_T thisRead = numBytesToRead; + + // If the total number of bytes to read exceeds the bytes remaining + // in the current strip, just read what can be read from the current strip. + if (numBytesToRead > remainingBytesInStrip) + { + thisRead = remainingBytesInStrip; + mStripIndex++; //increment the strip index for next time + } + + // Go to the offset, and read. + mInput->seek(seekPos, io::Seekable::START); + mInput->read((sys::byte *)buffer + bufferOffset, thisRead); + + // Update the tile position in bytes. + mBytePosition += thisRead; + + // Decrement the number of elements remaining to read. + numBytesToRead -= thisRead; + bufferOffset += thisRead; + + //reset to 0 + stripPosition = 0; + } +} + +void tiff::ImageReader::getTileData(unsigned char*buffer, + sys::Uint32_T numElementsToRead) +{ + // Get the image width and length. + sys::Uint32_T imageElemWidth = mIFD.getImageWidth(); + sys::Uint32_T imageByteWidth = imageElemWidth * mElementSize; + + // Get the tile width. + tiff::IFDEntry *tileWidth = mIFD["TileWidth"]; + sys::Uint32_T tileElemWidth = 0; + if (tileWidth->getType() == tiff::Const::Type::LONG) + tileElemWidth = *(tiff::GenericType *)(*tileWidth)[0]; + else + tileElemWidth = *(tiff::GenericType *)(*tileWidth)[0]; + sys::Uint32_T tileByteWidth = tileElemWidth * mElementSize; + + // Get the tile length. + tiff::IFDEntry *tileLength = mIFD["TileLength"]; + sys::Uint32_T tileElemLength = 0; + if (tileLength->getType() == tiff::Const::Type::LONG) + tileElemLength = *(tiff::GenericType *)(*tileLength)[0]; + else + tileElemLength = *(tiff::GenericType *)(*tileLength)[0]; + + // Compute the number of tiles wide the image is. + sys::Uint32_T tilesAcross = (imageElemWidth + tileElemWidth - 1) + / tileElemWidth; + + // Determine how many bytes were used to pad the right edge. + sys::Uint32_T widthPadding = (tileByteWidth * tilesAcross) - imageByteWidth; + sys::Uint32_T bufferOffset = 0; + + while (numElementsToRead) + { + sys::Uint32_T bytesToRead = mElementSize * numElementsToRead; + + // Compute the row in image, row in tile, and tile row. + sys::Uint32_T row = mBytePosition / imageByteWidth; + sys::Uint32_T tileRow = row / tileElemLength; + sys::Uint32_T rowInTile = row % tileElemLength; + + // Compute the column in image, column in tile, and tile column. + sys::Uint32_T column = mBytePosition - (row * imageByteWidth); + sys::Uint32_T tileColumn = column / tileByteWidth; + sys::Uint32_T colInTile = column % tileByteWidth; + + // Compute the 1D tile index from the tile row and tile column. + sys::Uint32_T tileIndex = (tileRow * tilesAcross) + tileColumn; + + sys::Uint32_T paddedBytes = ((tileColumn + 1) / tilesAcross) + * widthPadding; + + sys::Uint32_T remainingBytesThisLine = tileByteWidth - (paddedBytes + + (column % tileByteWidth)); + + // If the total number of bytes to read exceeds the bytes remaining + // in the current line of the current tile, just read what can be + // read from the current tile. + if (bytesToRead> remainingBytesThisLine) + bytesToRead = remainingBytesThisLine; + + // Seek to the tile offset plus the last read position. + tiff::IFDEntry *tileOffsets = mIFD["TileOffsets"]; + sys::Uint32_T seekPos = (*(tiff::GenericType *)(*tileOffsets)[tileIndex]) + (rowInTile * tileByteWidth) + + colInTile; + + // Go to the offset. + mInput->seek(seekPos, io::Seekable::START); + + // Read the data. + mInput->read((sys::byte *)buffer + bufferOffset, bytesToRead); + + // Update the strip position in bytes. + mBytePosition += bytesToRead; + + // Decrement the number of elements remaining to read. + bufferOffset += bytesToRead; + numElementsToRead -= (bytesToRead / mElementSize); + } +} diff --git a/modules/c++/tiff/source/ImageWriter.cpp b/modules/c++/tiff/source/ImageWriter.cpp new file mode 100644 index 000000000..68daec809 --- /dev/null +++ b/modules/c++/tiff/source/ImageWriter.cpp @@ -0,0 +1,487 @@ +/* ========================================================================= + * This file is part of tiff-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2011, General Dynamics - Advanced Information Systems + * + * tiff-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include "tiff/ImageWriter.h" + +#include +#include +#include + +#include "tiff/Common.h" +#include "tiff/GenericType.h" +#include "tiff/IFDEntry.h" + +const unsigned short tiff::ImageWriter::CHUNK_SIZE = 8192; + +void tiff::ImageWriter::putData(const unsigned char *buffer, + sys::Uint32_T numElementsToWrite) +{ + validate(); + + if (mFormat == TILED) + { + putTileData(buffer, numElementsToWrite); + } + else + { + putStripData(buffer, numElementsToWrite); + } +} + +void tiff::ImageWriter::writeIFD() +{ + // Retain the current file offset. + sys::Uint32_T offset = mOutput->tell(); + + // Seek to the position to write the current offset to. + mOutput->seek(mIFDOffset, io::Seekable::START); + + // Write the current offset. + mOutput->write((sys::byte *)&offset, sizeof(offset)); + + // Reseek to the current offset and write out the IFD. + mOutput->seek(offset, io::Seekable::START); + mIFD.serialize(*mOutput); + + // Keep the position in the file that the offset to the next + // IFD can be written to, in case there is another IFD. + mIFDOffset = mIFD.getNextIFDOffsetPosition(); +} + +void tiff::ImageWriter::validate() +{ + if (mValidated) + return; + + // ImageWidth + tiff::IFDEntry *imageWidth = mIFD["ImageWidth"]; + if (!imageWidth) + throw except::Exception(Ctxt("ImageWidth must be defined")); + + // ImageLength + tiff::IFDEntry *imageLength = mIFD["ImageLength"]; + if (!imageLength) + throw except::Exception(Ctxt("ImageLength must be defined")); + + // Compression + tiff::IFDEntry *compression = mIFD["Compression"]; + if (!compression) + mIFD.addEntry("Compression", (unsigned short) 1); + else + { + if (*(tiff::GenericType *)(*compression)[0] != 1) + throw except::Exception(Ctxt("Unsupported compression type")); + } + + // XResolution + tiff::IFDEntry *xResolution = mIFD["XResolution"]; + if (!xResolution) + { + mIFD.addEntry("XResolution", tiff::combine( + (sys::Uint32_T) 72, (sys::Uint32_T) 1)); + } + + // YResolution + tiff::IFDEntry *yResolution = mIFD["YResolution"]; + if (!yResolution) + { + mIFD.addEntry("YResolution", tiff::combine( + (sys::Uint32_T) 72, (sys::Uint32_T) 1)); + } + + // ResolutionUnit + tiff::IFDEntry *resolutionUnit = mIFD["ResolutionUnit"]; + if (!resolutionUnit) + mIFD.addEntry("ResolutionUnit", (unsigned short) 2); + + // SamplesPerPixel + tiff::IFDEntry *samplesPerPixel = mIFD["SamplesPerPixel"]; + unsigned short spp = (!samplesPerPixel) ? 0 + : (unsigned short)*(tiff::GenericType *)(*samplesPerPixel)[0]; + + // PhotometricInterpretation + tiff::IFDEntry *photoInterp = mIFD["PhotometricInterpretation"]; + if (!photoInterp) + throw except::Exception(Ctxt("No default for PhotometricInterpretation; it must be defined")); + + switch (*(tiff::GenericType *)(*photoInterp)[0]) + { + case tiff::Const::PhotoInterpType::BLACK_IS_ZERO: + case tiff::Const::PhotoInterpType::WHITE_IS_ZERO: + break; + + case tiff::Const::PhotoInterpType::RGB: + + if (!samplesPerPixel) + { + spp = 3; + mIFD.addEntry("SamplesPerPixel", (unsigned short) spp); + samplesPerPixel = mIFD["SamplesPerPixel"]; + } + else + { + if (spp < 3) + throw except::Exception(Ctxt("SamplesPerPixel must be at least 3 for RGB files")); + } + + break; + + case tiff::Const::PhotoInterpType::COLORMAP: + + if (!mIFD["ColorMap"]) + throw except::Exception(Ctxt("Colormap must be defined for ColorMapped files")); + + if (samplesPerPixel && *(tiff::GenericType *)(*samplesPerPixel)[0] != 1) + throw except::Exception(Ctxt("SamplesPerPixel must be 1 for ColorMapped files")); + + break; + + default: + throw except::Exception(Ctxt("Unsupported PhotometricInterpretation")); + } + + tiff::IFDEntry *bitsPerSample = mIFD["BitsPerSample"]; + if (samplesPerPixel) + { + for (int i = 0; i < spp; ++i) + { + if (!bitsPerSample) + mIFD.addEntry("BitsPerSample", (unsigned short) 8); + else + { + unsigned short bps = *(tiff::GenericType *)(*bitsPerSample)[0]; + + if (!(*bitsPerSample)[i]) + mIFD.addEntryValue("BitsPerSample", (unsigned short) bps); + else + { + unsigned short value = + *(tiff::GenericType *)(*bitsPerSample)[i]; + if (value != 8 && i < 3) + throw except::Exception(Ctxt("BitsPerSample values must be 8 for RGB files")); + } + } + + tiff::IFDEntry *sampleFormat = mIFD["SampleFormat"]; + if (sampleFormat) + { + unsigned short format = *(tiff::GenericType *)(*sampleFormat)[0]; + if (!(*sampleFormat)[i]) + mIFD.addEntryValue("SampleFormat", (unsigned short) format); + else + { + unsigned short value = + *(tiff::GenericType *)(*sampleFormat)[i]; + if (value != 1 && i < 3) + throw except::Exception(Ctxt("SampleFormat values must be 1 for RGB files")); + } + } + } + } + + if (!bitsPerSample) + mIFD.addEntry("BitsPerSample", (unsigned short) 8); + + mElementSize = mIFD.getElementSize(); + + if (mFormat == TILED) + initTiles(); + else + initStrips(); + + // if (mGeoTIFFReader) + // { + // tiff::IFDEntry *entry = NULL; + // if ((entry = (*mGeoTIFFReader)["ModelPixelScaleTag"])) + // mIFD.addEntry(entry); + // if ((entry = (*mGeoTIFFReader)["ModelTiepointTag"])) + // mIFD.addEntry(entry); + // if ((entry = (*mGeoTIFFReader)["ModelTransformationTag"])) + // mIFD.addEntry(entry); + // if ((entry = (*mGeoTIFFReader)["GeoKeyDirectoryTag"])) + // mIFD.addEntry(entry); + // if ((entry = (*mGeoTIFFReader)["GeoDoubleParamsTag"])) + // mIFD.addEntry(entry); + // if ((entry = (*mGeoTIFFReader)["GeoAsciiParamsTag"])) + // mIFD.addEntry(entry); + // } + + mValidated = true; +} + +void tiff::ImageWriter::initTiles() +{ + sys::Uint32_T root = (sys::Uint32_T)sqrt((double)mIdealChunkSize + / (double)mIFD.getElementSize()); + sys::Uint32_T ceiling = (sys::Uint32_T)ceil(((double)root) / 16); + sys::Uint32_T tileSize = ceiling * 16; + + mIFD.addEntry("TileWidth", (sys::Uint32_T) tileSize); + mIFD.addEntry("TileLength", (sys::Uint32_T) tileSize); + + sys::Uint32_T fileOffset = mOutput->tell(); + sys::Uint32_T tilesAcross = (mIFD.getImageWidth() + tileSize - 1) + / tileSize; + sys::Uint32_T tilesDown = (mIFD.getImageLength() + tileSize - 1) / tileSize; + + unsigned short elementSize = mIFD.getElementSize(); + + mIFD.addEntry("TileByteCounts"); + mIFD.addEntry("TileOffsets"); + for (sys::Uint32_T y = 0; y < tilesDown; ++y) + { + for (sys::Uint32_T x = 0; x < tilesAcross; ++x) + { + sys::Uint32_T byteCount = tileSize * tileSize * elementSize; + mIFD.addEntryValue("TileOffsets", (sys::Uint32_T) fileOffset); + mIFD.addEntryValue("TileByteCounts", (sys::Uint32_T) byteCount); + fileOffset += byteCount; + } + } + + mTileOffsets = mIFD["TileOffsets"]; + mTileWidth = mIFD["TileWidth"]; + mTileLength = mIFD["TileLength"]; + mTileByteCounts = mIFD["TileByteCounts"]; +} + +void tiff::ImageWriter::initStrips() +{ + sys::Uint32_T bytesPerLine = mIFD.getImageWidth() * mIFD.getElementSize(); + + sys::Uint32_T stripByteCount = 0; + sys::Uint32_T rowsPerStrip = 1; + if (bytesPerLine > mIdealChunkSize) + stripByteCount = bytesPerLine; + else + { + rowsPerStrip = (mIdealChunkSize + (mIdealChunkSize >> 1)) + / bytesPerLine; + stripByteCount = bytesPerLine * rowsPerStrip; + } + + mIFD.addEntry("RowsPerStrip", rowsPerStrip); + + sys::Uint32_T length = mIFD.getImageLength(); + sys::Uint32_T stripsPerImage = + (sys::Uint32_T)floor(static_cast(length + rowsPerStrip - 1) + / static_cast(rowsPerStrip)); + + sys::Uint32_T offset = mOutput->tell(); + + // Add counts and offsets for all but the last strip. + mIFD.addEntry("StripOffsets"); + mIFD.addEntry("StripByteCounts"); + for (sys::Uint32_T i = 0; i < stripsPerImage - 1; ++i) + { + mIFD.addEntryValue("StripOffsets", (sys::Uint32_T) offset); + mIFD.addEntryValue("StripByteCounts", (sys::Uint32_T) stripByteCount); + offset += stripByteCount; + } + + // Add the last offset. + mIFD.addEntryValue("StripOffsets", (sys::Uint32_T) offset); + + // The last byte count can be less than the previous counts. This occurs + // (for example) if RowsPerStrip is even, and ImageLength is odd. + sys::Uint32_T remainingBytes = mIFD.getImageSize() - ((stripsPerImage - 1) + * stripByteCount); + + // Add the last byteCount. + mIFD.addEntryValue("StripByteCounts", remainingBytes); + mStripByteCounts = mIFD["StripByteCounts"]; +} + +void tiff::ImageWriter::putTileData(const unsigned char *buffer, + sys::Uint32_T numElementsToWrite) +{ + sys::Uint32_T imageElemWidth = mIFD.getImageWidth(); + sys::Uint32_T imageByteWidth = imageElemWidth * mElementSize; + + sys::Uint32_T tileElemWidth = *(tiff::GenericType *)(*mTileWidth)[0]; + sys::Uint32_T tileByteWidth = tileElemWidth * mElementSize; + + unsigned short tileElemLength = *(tiff::GenericType *)(*mTileLength)[0]; + + // Compute the number of tiles wide the image is. + sys::Uint32_T tilesAcross = (imageElemWidth + tileElemWidth - 1) + / tileElemWidth; + + // Determine how many bytes were used to pad the right edge. + sys::Uint32_T widthPadding = (tileByteWidth * tilesAcross) - imageByteWidth; + sys::Uint32_T globalReadOffset = 0; + sys::Uint32_T tempBytePosition = mBytePosition; + sys::Uint32_T numBytesToWrite = numElementsToWrite * mElementSize; + sys::Uint32_T currentNumBytesRead = 0; + sys::Uint32_T remainingElementsToWrite = numElementsToWrite; + while (remainingElementsToWrite) + { + if (((mBytePosition + currentNumBytesRead) / imageByteWidth) + / tileElemLength > (tempBytePosition / imageByteWidth) + / tileElemLength) + { + tempBytePosition = mBytePosition + currentNumBytesRead; + globalReadOffset = currentNumBytesRead; + } + + // Compute the row and tile row. + sys::Uint32_T row = tempBytePosition / imageByteWidth; + sys::Uint32_T tileRow = row / tileElemLength; + + // Compute the column and tile column. + sys::Uint32_T column = tempBytePosition - (row * imageByteWidth); + sys::Uint32_T tileColumn = column / tileByteWidth; + + // Compute the 1D tile index from the tile row and tile column. + sys::Uint32_T tileIndex = (tileRow * tilesAcross) + tileColumn; + + sys::Uint32_T tileByteCount = *(tiff::GenericType *)(*mTileByteCounts)[tileIndex]; + + sys::Uint32_T rowInTile = row % tileElemLength; + sys::Uint32_T paddedBytes = ((tileColumn + 1) / tilesAcross) + * widthPadding; + + sys::Uint32_T remainingBytesInTile = tileByteCount - (tileElemLength + * paddedBytes) - (rowInTile * (tileByteWidth - paddedBytes) + + (column % tileByteWidth)); + + tempBytePosition += tileByteWidth - (paddedBytes + (column + % tileByteWidth)); + + sys::byte *copyBuffer = new sys::byte[tileByteWidth * tileElemLength]; + memset(copyBuffer, 0, tileByteWidth * tileElemLength); + sys::Uint32_T copyOffset = 0; + sys::Uint32_T readOffset = 0; + sys::Uint32_T tempColumn = column; + unsigned short iteration = 0; + while (readOffset < numBytesToWrite) + { + sys::Uint32_T remainingBytesThisLine = tileByteWidth - (paddedBytes + + (tempColumn % tileByteWidth)); + + sys::Uint32_T numBytesToCopy = remainingBytesThisLine; + + if (!remainingBytesInTile) + break; + + if (iteration == 0) + { + iteration++; + readOffset = globalReadOffset; + globalReadOffset += numBytesToCopy; + } + + if (numBytesToCopy > numBytesToWrite - readOffset) + numBytesToCopy = numBytesToWrite - readOffset; + + if (paddedBytes) + { + if (((tempColumn % tileByteWidth) + numBytesToCopy) + / (tileByteWidth - paddedBytes) == 0) + paddedBytes = 0; + } + + memcpy(copyBuffer + copyOffset, buffer + readOffset, numBytesToCopy); + copyOffset += (numBytesToCopy + paddedBytes); + readOffset += (imageByteWidth - (tempColumn % tileByteWidth)); + tempColumn -= (tempColumn % tileByteWidth); + remainingBytesInTile -= numBytesToCopy; + remainingElementsToWrite -= (numBytesToCopy / mElementSize); + currentNumBytesRead += numBytesToCopy; + } + + sys::Uint32_T seekPos = *(tiff::GenericType *)(*mTileOffsets)[tileIndex]; + seekPos += (row % tileElemLength) * tileByteWidth; + seekPos += (column % tileByteWidth); + mOutput->seek(seekPos, io::Seekable::START); + mOutput->write(copyBuffer, copyOffset); + delete [] copyBuffer; + } + + mBytePosition += numBytesToWrite; + + // All of the real data is in, just have to pad the bottom of the file. + if (mBytePosition == mIFD.getImageSize()) + { + sys::Uint32_T imageElemLength = mIFD.getImageLength(); + sys::Uint32_T tilesDown = (imageElemLength + tileElemLength - 1) + / tileElemLength; + sys::Uint32_T startIndex = (tilesDown - 1) * tilesAcross; + sys::Uint32_T paddingStartLine = imageElemLength % tileElemLength; + if (paddingStartLine) + { + sys::Uint32_T paddedLines = tileElemLength - paddingStartLine; + + sys::byte *padBuffer = new sys::byte[paddedLines * tileByteWidth]; + memset(padBuffer, 0, paddedLines * tileByteWidth); + + for (sys::Uint32_T i = 0; i < tilesAcross; ++i) + { + sys::Uint32_T seekPos = *(tiff::GenericType *)(*mTileOffsets)[startIndex + i]; + seekPos += paddingStartLine * tileByteWidth; + mOutput->seek(seekPos, io::Seekable::START); + mOutput->write(padBuffer, paddedLines * tileByteWidth); + } + + delete [] padBuffer; + } + + // If no padding, seek the end of the image. This is so that + // when the IFD is written, it doesn't try to write it into the + // middle of the file. This is a patch and a better solution + // should probably be found. + else + { + sys::Uint32_T lastTileIndex = mTileOffsets->getValues().size() - 1; + sys::Uint32_T seekPos = *(tiff::GenericType *)(*mTileOffsets)[lastTileIndex]; + seekPos += *(tiff::GenericType *)(*mTileByteCounts)[lastTileIndex]; + mOutput->seek(seekPos, io::Seekable::START); + } + } +} + +void tiff::ImageWriter::putStripData(const unsigned char *buffer, + sys::Uint32_T numElementsToWrite) +{ + sys::Uint32_T stripSize = *(tiff::GenericType *)(*mStripByteCounts)[0]; + sys::Uint32_T bufferIndex = 0; + + while (numElementsToWrite) + { + sys::Uint32_T bytesToWrite = mElementSize * numElementsToWrite; + sys::Uint32_T stripIndex = mBytePosition / stripSize; + sys::Uint32_T stripPosition = mBytePosition % stripSize; + + // Calculate what remains to be written in the current strip. + sys::Uint32_T remainingBytesInStrip = + (*(tiff::GenericType *)(*mStripByteCounts)[stripIndex]) - stripPosition; + + if (bytesToWrite > remainingBytesInStrip) + bytesToWrite = remainingBytesInStrip; + + mOutput->write((sys::byte *)buffer + bufferIndex, bytesToWrite); + bufferIndex += bytesToWrite; + + numElementsToWrite -= (bytesToWrite / mElementSize); + mBytePosition += bytesToWrite; + } +} diff --git a/modules/c++/tiff/source/KnownTags.cpp b/modules/c++/tiff/source/KnownTags.cpp new file mode 100644 index 000000000..7df8c246b --- /dev/null +++ b/modules/c++/tiff/source/KnownTags.cpp @@ -0,0 +1,166 @@ +/* ========================================================================= + * This file is part of tiff-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2011, General Dynamics - Advanced Information Systems + * + * tiff-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include "tiff/KnownTags.h" + +#include + +#include "tiff/Common.h" +#include "tiff/IFDEntry.h" +#include + +const char tiff::KnownTags::IMAGE_WIDTH[] = "ImageWidth"; +const char tiff::KnownTags::IMAGE_LENGTH[] = "ImageLength"; +const char tiff::KnownTags::BITS_PER_SAMPLE[] = "BitsPerSample"; +const char tiff::KnownTags::COMPRESSION[] = "Compression"; +const char tiff::KnownTags::SAMPLES_PER_PIXEL[] = "SamplesPerPixel"; +const char tiff::KnownTags::PHOTOMETRIC_INTERPRETATION[] = "PhotometricInterpretation"; +const char tiff::KnownTags::SAMPLE_FORMAT[] = "SampleFormat"; + +tiff::KnownTags::KnownTags() +{ + addEntry(254, tiff::Const::Type::LONG, "NewSubfileType"); + addEntry(255, tiff::Const::Type::SHORT, "SubfileType"); + addEntry(256, tiff::Const::Type::LONG, tiff::KnownTags::IMAGE_WIDTH); + addEntry(257, tiff::Const::Type::LONG, tiff::KnownTags::IMAGE_LENGTH); + addEntry(258, tiff::Const::Type::SHORT, tiff::KnownTags::BITS_PER_SAMPLE); + addEntry(259, tiff::Const::Type::SHORT, tiff::KnownTags::COMPRESSION); + addEntry(262, tiff::Const::Type::SHORT, tiff::KnownTags::PHOTOMETRIC_INTERPRETATION); + addEntry(263, tiff::Const::Type::SHORT, "Thresholding"); + addEntry(264, tiff::Const::Type::SHORT, "CellWidth"); + addEntry(265, tiff::Const::Type::SHORT, "CellLength"); + addEntry(266, tiff::Const::Type::SHORT, "FillOrder"); + addEntry(269, tiff::Const::Type::ASCII, "DocumentName"); + addEntry(270, tiff::Const::Type::ASCII, "ImageDescription"); + addEntry(271, tiff::Const::Type::ASCII, "Make"); + addEntry(272, tiff::Const::Type::ASCII, "Model"); + addEntry(273, tiff::Const::Type::LONG, "StripOffsets"); + addEntry(274, tiff::Const::Type::SHORT, "Orientation"); + addEntry(277, tiff::Const::Type::SHORT, tiff::KnownTags::SAMPLES_PER_PIXEL); + addEntry(278, tiff::Const::Type::LONG, "RowsPerStrip"); + addEntry(279, tiff::Const::Type::LONG, "StripByteCounts"); + addEntry(280, tiff::Const::Type::SHORT, "MinSampleValue"); + addEntry(281, tiff::Const::Type::SHORT, "MaxSampleValue"); + addEntry(282, tiff::Const::Type::RATIONAL, "XResolution"); + addEntry(283, tiff::Const::Type::RATIONAL, "YResolution"); + addEntry(284, tiff::Const::Type::SHORT, "PlanarConfiguration"); + addEntry(285, tiff::Const::Type::ASCII, "PageName"); + addEntry(286, tiff::Const::Type::RATIONAL, "XPosition"); + addEntry(287, tiff::Const::Type::RATIONAL, "YPosition"); + addEntry(288, tiff::Const::Type::LONG, "FreeOffsets"); + addEntry(289, tiff::Const::Type::LONG, "FreeByteCounts"); + addEntry(290, tiff::Const::Type::SHORT, "GrayResponseUnit"); + addEntry(291, tiff::Const::Type::SHORT, "GrayResponseCurve"); + addEntry(292, tiff::Const::Type::LONG, "T4Options"); + addEntry(293, tiff::Const::Type::LONG, "T6Options"); + addEntry(296, tiff::Const::Type::SHORT, "ResolutionUnit"); + addEntry(297, tiff::Const::Type::SHORT, "PageNumber"); + addEntry(301, tiff::Const::Type::SHORT, "TransferFunction"); + addEntry(305, tiff::Const::Type::ASCII, "Software"); + addEntry(306, tiff::Const::Type::ASCII, "DateTime"); + addEntry(315, tiff::Const::Type::ASCII, "Artist"); + addEntry(316, tiff::Const::Type::ASCII, "HostComputer"); + addEntry(317, tiff::Const::Type::SHORT, "Predictor"); + addEntry(318, tiff::Const::Type::RATIONAL, "WhitePoint"); + addEntry(319, tiff::Const::Type::RATIONAL, "PrimaryChromaticities"); + addEntry(320, tiff::Const::Type::SHORT, "ColorMap"); + addEntry(321, tiff::Const::Type::SHORT, "HalftoneHints"); + addEntry(322, tiff::Const::Type::LONG, "TileWidth"); + addEntry(323, tiff::Const::Type::LONG, "TileLength"); + addEntry(324, tiff::Const::Type::LONG, "TileOffsets"); + addEntry(325, tiff::Const::Type::LONG, "TileByteCounts"); + addEntry(326, tiff::Const::Type::LONG, "BadFaxLines"); + addEntry(327, tiff::Const::Type::LONG, "CleanFaxData"); + addEntry(328, tiff::Const::Type::LONG, "ConsecutiveBadFaxLines"); + addEntry(332, tiff::Const::Type::SHORT, "InkSet"); + addEntry(333, tiff::Const::Type::ASCII, "InkNames"); + addEntry(334, tiff::Const::Type::SHORT, "NumberOfInks"); + addEntry(336, tiff::Const::Type::SHORT, "DotRange"); + addEntry(337, tiff::Const::Type::ASCII, "TargetPrinter"); + addEntry(338, tiff::Const::Type::SHORT, "ExtraSamples"); + addEntry(339, tiff::Const::Type::SHORT, tiff::KnownTags::SAMPLE_FORMAT); + addEntry(340, tiff::Const::Type::UNDEFINED, "SMinSampleValue"); + addEntry(341, tiff::Const::Type::UNDEFINED, "SMaxSampleValue"); + addEntry(342, tiff::Const::Type::SHORT, "TransferRange"); + addEntry(512, tiff::Const::Type::SHORT, "JPEGProc"); + addEntry(513, tiff::Const::Type::LONG, "JPEGInterchangeFormat"); + addEntry(514, tiff::Const::Type::LONG, "JPEGInterchangeFormatLngth"); + addEntry(515, tiff::Const::Type::SHORT, "JPEGRestartInterval"); + addEntry(517, tiff::Const::Type::SHORT, "JPEGLosslessPredictors"); + addEntry(518, tiff::Const::Type::SHORT, "JPEGPointTransforms"); + addEntry(519, tiff::Const::Type::LONG, "JPEGQTables"); + addEntry(520, tiff::Const::Type::LONG, "JPEGDCTables"); + addEntry(521, tiff::Const::Type::LONG, "JPEGACTables"); + addEntry(529, tiff::Const::Type::RATIONAL, "YCbCrCoefficients"); + addEntry(530, tiff::Const::Type::SHORT, "YCbCrSubSampling"); + addEntry(531, tiff::Const::Type::SHORT, "YCbCrPositioning"); + addEntry(532, tiff::Const::Type::LONG, "ReferenceBlackWhite"); + addEntry(559, tiff::Const::Type::LONG, "StripRowCounts"); + addEntry(700, tiff::Const::Type::BYTE, "XMP"); + addEntry(32781, tiff::Const::Type::ASCII, "ImageID"); + addEntry(33432, tiff::Const::Type::ASCII, "Copyright"); + addEntry(34732, tiff::Const::Type::LONG, "ImageLayer"); + + // GeoTIFF Tags + addEntry(33550, tiff::Const::Type::DOUBLE, "ModelPixelScaleTag"); + addEntry(33922, tiff::Const::Type::DOUBLE, "ModelTiepointTag"); + addEntry(34264, tiff::Const::Type::DOUBLE, "ModelTransformationTag"); + addEntry(34735, tiff::Const::Type::SHORT, "GeoKeyDirectoryTag"); + addEntry(34736, tiff::Const::Type::DOUBLE, "GeoDoubleParamsTag"); + addEntry(34737, tiff::Const::Type::ASCII, "GeoAsciiParamsTag"); +} + + +tiff::KnownTags::~KnownTags() +{ + for(std::map::iterator it = mKnownTags.begin(); + it != mKnownTags.end(); ++it) + delete it->second; + mKnownTags.clear(); +} + +void tiff::KnownTags::addEntry(const unsigned short tag, + const unsigned short type, + const std::string& name) +{ + std::map::iterator pos = + mKnownTags.find(tag); + if (pos != mKnownTags.end()) + return; + + mNameMap[name] = tag; + mKnownTags[tag] = new tiff::IFDEntry(tag, type, name); +} + +tiff::IFDEntry *tiff::KnownTags::operator[] (const std::string& nameKey) +{ + unsigned short tagKey = mNameMap[nameKey]; + return (*this)[tagKey]; +} + +tiff::IFDEntry *tiff::KnownTags::operator[] (const unsigned short tagKey) +{ + std::map::iterator pos = + mKnownTags.find(tagKey); + return pos != mKnownTags.end() ? pos->second : NULL; +} + diff --git a/modules/c++/tiff/source/TypeFactory.cpp b/modules/c++/tiff/source/TypeFactory.cpp new file mode 100644 index 000000000..8c28d750e --- /dev/null +++ b/modules/c++/tiff/source/TypeFactory.cpp @@ -0,0 +1,76 @@ +/* ========================================================================= + * This file is part of tiff-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2011, General Dynamics - Advanced Information Systems + * + * tiff-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include "tiff/TypeFactory.h" +#include "tiff/Common.h" +#include "tiff/GenericType.h" +#include + +tiff::TypeInterface *tiff::TypeFactory::create(const unsigned char *data, + const unsigned short type) +{ + tiff::TypeInterface *tiffType = NULL; + switch (type) + { + case tiff::Const::Type::BYTE: + tiffType = new tiff::GenericType(data); + break; + case tiff::Const::Type::ASCII: + tiffType = new tiff::GenericType(data); + break; + case tiff::Const::Type::SHORT: + tiffType = new tiff::GenericType(data); + break; + case tiff::Const::Type::LONG: + tiffType = new tiff::GenericType(data); + break; + case tiff::Const::Type::RATIONAL: + tiffType = new tiff::GenericType(data); + break; + case tiff::Const::Type::SBYTE: + tiffType = new tiff::GenericType(data); + break; + case tiff::Const::Type::UNDEFINED: + tiffType = new tiff::GenericType(data); + break; + case tiff::Const::Type::SSHORT: + tiffType = new tiff::GenericType(data); + break; + case tiff::Const::Type::SLONG: + tiffType = new tiff::GenericType(data); + break; + case tiff::Const::Type::SRATIONAL: + tiffType = new tiff::GenericType(data); + break; + case tiff::Const::Type::FLOAT: + tiffType = new tiff::GenericType(data); + break; + case tiff::Const::Type::DOUBLE: + tiffType = new tiff::GenericType(data); + break; + default: + throw except::Exception(Ctxt("Unsupported Type")); + } + return tiffType; +} diff --git a/modules/c++/tiff/source/Utils.cpp b/modules/c++/tiff/source/Utils.cpp new file mode 100644 index 000000000..da7b77da9 --- /dev/null +++ b/modules/c++/tiff/source/Utils.cpp @@ -0,0 +1,181 @@ +/* ========================================================================= + * This file is part of tiff-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2011, General Dynamics - Advanced Information Systems + * + * tiff-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include "tiff/Utils.h" + +bool tiff::Utils::hasGeoTiffIFD(tiff::IFD* ifd) +{ + return ifd->exists("GeoKeyDirectoryTag"); +} + +tiff::IFD* tiff::Utils::createGeoTiffIFD(tiff::IFD* ifd) +{ + if (!tiff::Utils::hasGeoTiffIFD(ifd)) + return NULL; + + std::map keyMap; + keyMap[1024] = "GTModelTypeGeoKey"; + keyMap[1025] = "GTRasterTypeGeoKey"; + keyMap[1026] = "GTCitationGeoKey"; + keyMap[2048] = "GeographicTypeGeoKey"; + keyMap[2049] = "GeogCitationGeoKey"; + keyMap[2050] = "GeogGeodeticDatumGeoKey"; + keyMap[2051] = "GeogPrimeMeridianGeoKey"; + keyMap[2061] = "GeogPrimeMeridianLongGeoKey"; + keyMap[2052] = "GeogLinearUnitsGeoKey"; + keyMap[2053] = "GeogLinearUnitSizeGeoKey"; + keyMap[2054] = "GeogAngularUnitsGeoKey"; + keyMap[2055] = "GeogAngularUnitSizeGeoKey"; + keyMap[2056] = "GeogEllipsoidGeoKey"; + keyMap[2057] = "GeogSemiMajorAxisGeoKey"; + keyMap[2058] = "GeogSemiMinorAxisGeoKey"; + keyMap[2059] = "GeogInvFlatteningGeoKey"; + keyMap[2060] = "GeogAzimuthUnitsGeoKey"; + keyMap[3072] = "ProjectedCSTypeGeoKey"; + keyMap[3073] = "PCSCitationGeoKey"; + keyMap[3074] = "ProjectionGeoKey"; + keyMap[3075] = "ProjCoordTransGeoKey"; + keyMap[3076] = "ProjLinearUnitsGeoKey"; + keyMap[3077] = "ProjLinearUnitSizeGeoKey"; + keyMap[3078] = "ProjStdParallel1GeoKey"; + keyMap[3079] = "ProjStdParallel2GeoKey"; + keyMap[3080] = "ProjNatOriginLongGeoKey"; + keyMap[3081] = "ProjNatOriginLatGeoKey"; + keyMap[3082] = "ProjFalseEastingGeoKey"; + keyMap[3083] = "ProjFalseNorthingGeoKey"; + keyMap[3084] = "ProjFalseOriginLongGeoKey"; + keyMap[3085] = "ProjFalseOriginLatGeoKey"; + keyMap[3086] = "ProjFalseOriginEastingGeoKey"; + keyMap[3087] = "ProjFalseOriginNorthingGeoKey"; + keyMap[3088] = "ProjCenterLongGeoKey"; + keyMap[3089] = "ProjCenterLatGeoKey"; + keyMap[3090] = "ProjCenterEastingGeoKey"; + keyMap[3091] = "ProjFalseOriginNorthingGeoKey"; + keyMap[3092] = "ProjScaleAtNatOriginGeoKey"; + keyMap[3093] = "ProjScaleAtCenterGeoKey"; + keyMap[3094] = "ProjAzimuthAngleGeoKey"; + keyMap[3095] = "ProjStraightVertPoleLongGeoKey"; + keyMap[2060] = "GeogAzimuthUnitsGeoKey"; + keyMap[4096] = "VerticalCSTypeGeoKey"; + keyMap[4097] = "VerticalCitationGeoKey"; + keyMap[4098] = "VerticalDatumGeoKey"; + keyMap[4099] = "VerticalUnitsGeoKey"; + + tiff::IFD* geoIFD = new tiff::IFD; + + tiff::IFDEntry *geoDir = (*ifd)["GeoKeyDirectoryTag"]; + tiff::IFDEntry *doubleParams = + ifd->exists("GeoDoubleParamsTag") ? (*ifd)["GeoDoubleParamsTag"] + : NULL; + tiff::IFDEntry *asciiParams = + ifd->exists("GeoAsciiParamsTag") ? (*ifd)["GeoAsciiParamsTag"] + : NULL; + + std::vector geoVals = geoDir->getValues(); + size_t idx = 0; + + + str::toType(geoVals[idx++]->toString()); // skipping keyDirVersion + str::toType(geoVals[idx++]->toString()); // skipping keyRevision + str::toType(geoVals[idx++]->toString()); // skipping keyRevisionMinor + const unsigned short numKeys = + str::toType(geoVals[idx++]->toString()); + + for (unsigned short i = 0; i < numKeys; ++i) + { + // Ensure idx is in range + if (idx + 3 >= geoVals.size()) + { + throw except::Exception(Ctxt( + "'GeoKeyDirectoryTag' specified " + + str::toString(numKeys) + " keys but the IFD entry only had " + + str::toString(geoVals.size()) + " values")); + } + + const unsigned short keyId = + str::toType(geoVals[idx++]->toString()); + const unsigned short tiffTagLoc = + str::toType(geoVals[idx++]->toString()); + const unsigned short count = + str::toType(geoVals[idx++]->toString()); + const std::string valueStr(geoVals[idx++]->toString()); + + unsigned short entryType; + switch (tiffTagLoc) + { + case 34736: // GeoDoubleParamsTag + entryType = tiff::Const::Type::DOUBLE; + break; + case 34737: // GeoAsciiParamsTag + entryType = tiff::Const::Type::ASCII; + break; + default: + entryType = tiff::Const::Type::SHORT; + break; + } + + const std::map::const_iterator iter = + keyMap.find(keyId); + const std::string name = (iter == keyMap.end()) ? "" : iter->second; + + tiff::IFDEntry *entry = new tiff::IFDEntry(keyId, entryType, name); + + if (tiffTagLoc == 0) + { + if (count != 1) + { + throw except::Exception(Ctxt( + "Expected a count of 1 but got " + str::toString(count))); + } + + entry->addValue(new tiff::GenericType(valueStr)); + } + else if (tiffTagLoc == 34736 && doubleParams) + { + const unsigned short valueOffset = + str::toType(valueStr); + for (unsigned short j = 0; j < count; ++j) + { + entry->addValue( + new tiff::GenericType( + (*doubleParams)[valueOffset + + j]->toString())); + } + } + else if (tiffTagLoc == 34737 && asciiParams) + { + const unsigned short valueOffset = + str::toType(valueStr); + for (unsigned short j = 0; j < count; ++j) + { + entry->addValue( + new tiff::GenericType( + (*asciiParams)[valueOffset + + j]->toString())); + } + } + + geoIFD->addEntry(entry); + } + + return geoIFD; +} diff --git a/modules/c++/tiff/tests/DumpHeader.cpp b/modules/c++/tiff/tests/DumpHeader.cpp new file mode 100644 index 000000000..60668911a --- /dev/null +++ b/modules/c++/tiff/tests/DumpHeader.cpp @@ -0,0 +1,70 @@ +/* ========================================================================= + * This file is part of tiff-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2011, General Dynamics - Advanced Information Systems + * + * tiff-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include +#include +#include +#include +#include + +int main(int argc, char **argv) +{ + try + { + if (argc < 2) + throw except::Exception(FmtX("usage: %s ", argv[0])); + + sys::OS os; + std::string path = sys::Path::absolutePath(argv[1]); + if (!os.exists(path)) + throw except::FileNotFoundException(path); + + io::StandardOutStream outStream; + tiff::FileReader reader(path); + reader.print(outStream); + + for (sys::Uint32_T i = 0, n = reader.getImageCount(); i < n; ++i) + { + if (tiff::Utils::hasGeoTiffIFD(reader[i]->getIFD())) + { + outStream.writeln("==========================="); + outStream.writeln(FmtX("GeoTIFF detected: Image %d\n", (i + 1))); + tiff::IFD *geoIFD = + tiff::Utils::createGeoTiffIFD(reader[i]->getIFD()); + geoIFD->print(outStream); + outStream.writeln("==========================="); + delete geoIFD; + } + } + } + catch (except::Throwable& t) + { + std::cerr << t.toString() << std::endl; + exit( EXIT_FAILURE); + } + catch (...) + { + std::cerr << "Caught unnamed exception" << std::endl; + exit( EXIT_FAILURE); + } + return 0; +} diff --git a/modules/c++/tiff/tests/HeaderTest.cpp b/modules/c++/tiff/tests/HeaderTest.cpp new file mode 100644 index 000000000..888d491d2 --- /dev/null +++ b/modules/c++/tiff/tests/HeaderTest.cpp @@ -0,0 +1,53 @@ +/* ========================================================================= + * This file is part of tiff-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2011, General Dynamics - Advanced Information Systems + * + * tiff-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include +#include +#include +#include + +using namespace sys; + +int main(int argc, char **argv) +{ + try + { + io::StandardOutStream st; + tiff::IFDEntry entry(254, 1); + entry.print(st); + entry.print(st); + + tiff::IFDEntry entry2(255, 1); + entry2.print(st); + entry2.print(st); + } + catch (except::Throwable& t) + { + std::cerr << "Caught throwable: " << t.toString() << std::endl; + exit( EXIT_FAILURE); + } + catch (...) + { + std::cerr << "Caught unnamed exception" << std::endl; + } + return 0; +} diff --git a/modules/c++/tiff/wscript b/modules/c++/tiff/wscript new file mode 100644 index 000000000..53913616c --- /dev/null +++ b/modules/c++/tiff/wscript @@ -0,0 +1,9 @@ +NAME = 'tiff' +MAINTAINER = 'jmrandol@users.sourceforge.net' +VERSION = '1.0' +MODULE_DEPS = 'mt io' + +options = configure = distclean = lambda p: None + +def build(bld): + bld.module(**globals()) diff --git a/modules/c++/xml.lite/doc/GettingStarted.html b/modules/c++/xml.lite/doc/GettingStarted.html new file mode 100644 index 000000000..0e80f17f4 --- /dev/null +++ b/modules/c++/xml.lite/doc/GettingStarted.html @@ -0,0 +1,416 @@ + + +Getting Started With XML and xml.lite + + +

Getting Started With XML and xml.lite

+
+ +

Abstract

+ +

+This article teaches you how to use the XML utilities provided in +xml.lite and offers insight into choosing the right implementations +for you. It assumes that you have little experience using XML, but you +are familiar with the basics of it (on paper), and it guides you from there. +

+ +

Seeing XML for the First Time

+ +

+Realistically, you may never have seen XML, or you may not be very familiar +with XML documents. This article focuses on the toolkit API for using +XML, not on the structure of XML. If you need a quick briefing on what XML +is and how its used, consult any or all of the links below: + + ... +

+ +

DOM vs. SAX

+ +

Frequent XML users will be familiar with the difference between DOM and +SAX parser, and may wish to move on. xml.lite provides nearly the +entire SAX2 (namespace enabled) specification, and the important +basic DOM structures. As we explore the differences, you will +come to have an understanding of which type of parsing is right for you.

+ +

+As implied by the name, xml.lite subscribes to the notion that +programming XML should be as trivial as possible. The implementation follows +that of PyXML with its "sax driver" approach, as well as the perl and php +implementations. In other words, we build a simple DOM tree using an +underlying SAX parser (we call it a driver). SAX is an Acronym for Simple +API for XML. What it really means, though, is "event-driven" parser. SAX +is based on the notion of callbacks, and every time that it picks up some +data from an XML document, it calls up some functions. Briefly, these +functions are associated with: +

    +
  1. Beginning tags and attributes
  2. +
  3. Ending tag
  4. +
  5. Character data
  6. +
  7. Namespace mappings
  8. +
  9. DTD handlers
  10. +
  11. Comments
  12. +
+ +Note that in the current implementations, DTDs are not supported by +xml.lite's sax driver. This will be updated soon, however, we strongly +favor XMLSchemas instead of DTDs which are nearing deprecation. +SAX is much faster and leaner that DOM for loading, but content must +be handled by the user. In other words, a developer must inherit the +SAX ContentHandler class and describe what to do with the inputs. This +works well on simple XML structures but it is tedious for complex ones. +For almost all uses, I recommend the DOM model instead. +

+ +

DOM is an acronynm for Document Object Model. What this means is that +it builds an image of the document as a tree in memory. This can lead to +a much larger memory footprint, which may make it undesirable for larger +programs with strict memory constraints (the author has found that, in +practice, this is rarely the case).

+ + + + + + + +

Your first XML processing

+ +The code snippet below simply reads an XML document into a tree, and prints +the tree to the command line: + + + +
+   io::StandardOutStream out;
+   xml::lite::MinidomParser p;
+   p.parse( io::FileInputStream( "myfile.xml" );
+   xml::lite::Element* root = p->getDocument()->getRootElement();   
+   root->print(out);
+
+ + +We could even use a URL, which often contain XML. For instance, if you +have an xhtml document, point your parse() method at it instead: + +
+   p.parse( net::http::URLInputStream( "http://sei1.erim-int.com/blah/index.xhtml" );
+
+ +

Manipulating Elements

+Now say that we want to print our element information, but only if +the tag is named <print>. + +e.g., + +
+<ex>
+  <print>Hello World.</print>
+  <code>
+  <c>printf("Hello World.\n");</c>
+  <perl>print "Hello World.\n";</perl>
+  <php>echo "Hello World.\n";</php>
+  <java>System.out.println("Hello World.");</java>
+  </code>
+  <print>Goodbye Cruel World.</print>
+</ex>
+
+ +We can easily print only that information, very simply: + +
+xml::lite::MinidomParser p;
+p.parse( file );
+xml::lite::Element* root = p->getDocument()->getRootElement();
+std::vector<Element*> elements;
+// This will return two elements
+root->getElementsByTagName( "print", elements);
+for (int i = 0; i < elements.size(); i++)
+{
+   cout << elements[i].getCharacterData() << endl;
+}
+
+
+ +This will print: + +
+Hello World.
+Goodbye Cruel World.
+
+ +Now let's say that we want to get the code section, determine if +there is a language that the user requested, and print the +program code for Hello World from it. + +
    +
  1. User starts our program with the input language
  2. +
  3. We search for that language in the above file
  4. +
      +
    • If it does not exist, we report that we couldnt find it
    • +
    • If it does, we retrieve it and print the code for it to standard out
    • +
    +
+ + +
+
+
+#include <import/except.h>
+#include <import/sys.h>
+#include <import/io.h>
+#include <import/xml/lite.h>
+using namespace except;
+using namespace sys;
+using namespace io;
+using namespace xml::lite;
+
+using namespace std;
+
+int main(int argc, char **argv)
+{
+  try
+  {
+     if (argc != 2)
+     {
+         die_printf("Usage: hello_world \n");
+     }
+     MinidomParser p;
+     p.parse("langdb.xml");
+
+     Element* root = p.getDocument()->getRootElement();
+     if (! root->hasElement("code")
+        __raise__(NoSuchKeyException( "code" );
+     
+     std::vector<Element*> e;
+     
+     root->getElementsByTagName( "code", e);
+     
+     // We will only read the first element named code under 'ex'
+     if (! e[0]->hasElement( argv[1] ); // The language doesnt exist
+         cout << "No such language in the database.  Sorry..." << endl;
+
+     else 
+     {
+         Element* theLanguage = e[0]->getElementsByTagName( argv[1] );
+	 cout <<	 theLanguage->getCharacterData() << endl;
+
+     } 
+
+  }
+  catch (Error& e)
+  {
+     cerr << "Caught error: " << e.getMessage() << endl;
+  }
+  catch (Exception& x)
+  {
+     cerr << "Caught exception: " << x.getMessage() << endl;
+  }
+  catch (...)
+  {
+     cerr << "Caught unnamed exception" << endl;
+  }
+  return 0;
+}
+
+ +

Trimming hedges

+ + +Say I have grow disillusioned with my disillusionment, and I wish to +remove my "Cruel World" statement. + +I could change it like so: + +
+   root->getElementsByTagName("print", e);
+   // Remember that e[1] contains the second print, and e[0] is hello world
+   e[1]->setCharacterData("Goodbye World");
+
+ +That will change the value within the tree. Simple enough; but what if I +think its not only obnoxious, but its distracting the above program's functionality. After all, I dont have any code example, and it wouldnt be any +different from the 'hello world' code anyway. + + + +

Tangent: Who owns what

+If you are using a MinidomParser, you must understand that IT +owns the tree elements, not you. This differs from auto_ptr based systems, +etc. This prevents multiple copies from being explicitly created. When +you use an accessor and retrieve node, you must not delete it using delete. +Use the tree's remove() method to drop nodes. + +

Ok, Let's just get rid of it: + + +

+   // Lets remove it and all sub-components from the tree.
+   Document* doc =   p.getDocument();
+   Element* root =   doc->getRootElement();
+   ...
+   doc->remove(e[1]);
+   
+   // Can't use e[1] anymore, it is null
+   
+   // I can now prove its gone from the tree
+   root->print();
+
+
+ +

What is an XMLSchema?

+ +

A schema is a way of organizing and validating data in XML. +It is very complicated and very irritating, but the service +that it provides is absolutely necessary.

+ +

The general idea with XMLSchema is that you use an XML document to +'validate' another XML document. You then use a special meta-document +for that meta-document, developed by the W3C committee to create your +meta-document, or schema. Sounds confusing? It is, but the good news +is that most of you wont need to worry about schemas for now. Just know +that they are out there. However, if you want to know more, check out the +XML Schema documentation +for more information

+ + + +

Tags, Namespaces and QNames

+ +

When SAX came out, there were no namespaces in XML. This made everything +really simple. Everyone knew that you couldnt name two tags the same thing, +and, though cumbersome, folks accepted that. XML soon become a standard +for processing data, which meant that large chunks of data had to be transferred +around. Obviously, when referencing (including) other documents all over +an already large XML document, the chances of naming conflicts grow substantially. The XML gods became worried, and made a recommendation for namespaces in XML document. In the beginning, +nobody supported namespaces, and, well, nobody used them either. + +

When XMLSchema (see xs documentation), +and later SOAP (see xml.soap documentation) came out, developers started +scrambling to support namespaces, and interfaces once noted for their simplicity (ok, DOM never was simple, but remember that for SAX, simple is in the name), +became much uglier. Briefly, the way that namespaces are handled in XML is +as follows: +

    +
  1. Tags come in two parts, the local name and the prefix. + This is called a QName
  2. +
  3. Each QName has an associated uri that is a real document + describing the types declared in that QName
  4. +
  5. QNames go out of scope when the tag bearing the uri declaration + is popped off of the stack.
  6. +
+

+ +

Simply put, here is the anatomy of a tag: + +

+<prefix:localName>
+
+where prefix was mapped to a real live uri in such a manner: + +
+<sometag xmlns:prefix="uri">
+
+ +and uri is a site containg a declaration of the type of localName, +using XMLSchema. The good news is, once again, you probably wont need +this for basic XML processing for quite some time (unless you are +using XML/SOAP). + +

What About Attributes?

+ +

Attributes are key-value pairs that are allowed to follow a tag. +They appear immediately following the tag, and they are stored as +essentially a list. Attributes also may have namespaces from or until +the tag which declares that namespace goes out of scope. This is +frustrating for many programmers, who will likely choose to forget namespaces +altogether, but for substantial applications, this support is necessary. +For better or for worse, I chose to implement +the SAX2 API here, instead of a more C++-tuned approach (with maybe an Attributes object implemented as an STL vector instead. The internal storage, for the record, is currently a std::vector< xml::lite::AttributeNode >. +This is a more consistant approach with other languages and the SAX spec, and +therefore I chose it over some slicker counterpart. +

+ + +
+   // xml::lite::Element* e = some node;
+   xml::lite::Attributes attrs;
+   e->getAttributes( attrs );
+   for (int i = 0; i < attrs.getLength(); i++)
+   {
+       cout << "Key: " << attrs.getLocalName( i ) << endl;;
+       cout << "Value: " << attrs.getValue( i ) << endl;;
+   } 
+
+
+ + +

Using SAX: Simple Example

+Let's say that all I want to do is print this document in color coding. +Maybe I have a syntax highlighting screen API like curses, or maybe the +result goes to a editor: + +
+
+class SmartPrint : public xml::lite::ContentHandler
+{
+public:
+  SmartPrint(MyXMLDisplay* display) : mDisplay(display) {}
+  ~SmartPrint() {}
+  
+  void startElement( const std::string& uri, 
+                     const std::string& localName,
+                     const std::string& qname,
+                     const xml::lite::Attributes& attr )
+  {
+      mDisplay->beginTagInColor( qname, attr );
+      crossRef( uri );      
+  }
+  void endElement( const std::string& uri, 
+                   const std::string& localName,
+                   const std::string& qname )
+  {
+      mDisplay->endTagInColor( qname );
+      
+  }
+
+  void characters( const char* data, int length)
+  {
+      mDisplay->charDataInColor( data, length );
+  } 
+private:
+  MyXMLDisplay* mDisplay;
+  ...
+};
+
+
+ +To bind this code to our SAX reader, we can set the content handler: + +
+
+// Probably X for Unix and Win32 for Windows, but could be console
+MyXMLDisplay* display = MyXMLDisplayFactory::createDisplay();
+
+XMLReader reader;
+
+reader.setContentHandler( new SmartPrint( display ) );
+
+// This shows the code in the display area
+reader.parse( document );
+
+
+ +

SAX is Complicated but Powerful

+ +

Because xml.lite's SAX2 interface is very similar to the +original, you may refer to the SAX2 specificationfor more +details on how to implement SAX code. The code should be similar +or identical across systems, libraries, and even languages. Actually, the +same is true for DOM, both were designed for a common API. SAX is actually +a Java specification, but it was so popular that it has a binding in +many languages now. + + + + diff --git a/modules/c++/xml.lite/include/import/xml/lite.h b/modules/c++/xml.lite/include/import/xml/lite.h new file mode 100644 index 000000000..3736bfbc4 --- /dev/null +++ b/modules/c++/xml.lite/include/import/xml/lite.h @@ -0,0 +1,53 @@ +/* ========================================================================= + * This file is part of xml.lite-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2011, General Dynamics - Advanced Information Systems + * + * xml.lite-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __IMPORT_XML_LITE_H__ +#define __IMPORT_XML_LITE_H__ + +#include "xml/lite/ContentHandler.h" +#include "xml/lite/Attributes.h" +#include "xml/lite/QName.h" +#include "xml/lite/NamespaceStack.h" +#include "xml/lite/Document.h" +#include "xml/lite/Element.h" +#include "xml/lite/XMLException.h" +#include "xml/lite/XMLReader.h" +#include "xml/lite/MinidomHandler.h" +#include "xml/lite/MinidomParser.h" +#include "xml/lite/Serializable.h" +#include "xml/lite/Validator.h" + +/*! + * \file lite.h + * + * The xml.lite is a simple lightweight API for XML programming. + * It is based on the PHP, Perl and Python implementations. The + * idea behind it is that it avoids much of the bloat of W3C specifications, + * particularly the notorious DOM specifications, leaving the practical + * API's and discarding the overly-complex or confusing ones. + * + * Getting started with xml.lite is fairly straight-forward, with the + * assistance of the quickstart article + * + */ + +#endif diff --git a/modules/c++/xml.lite/include/xml/lite/Attributes.h b/modules/c++/xml.lite/include/xml/lite/Attributes.h new file mode 100644 index 000000000..ede55b774 --- /dev/null +++ b/modules/c++/xml.lite/include/xml/lite/Attributes.h @@ -0,0 +1,339 @@ +/* ========================================================================= + * This file is part of xml.lite-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2011, General Dynamics - Advanced Information Systems + * + * xml.lite-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __XML_LITE_ATTRIBUTES_H__ +#define __XML_LITE_ATTRIBUTES_H__ + +#include "sys/Conf.h" +#include "except/Exception.h" +#include "xml/lite/QName.h" +#include +#include + +/*! + * \file Attributes.h + * \brief Implementation of SAX 2.0 Attributes + * + * This file contains all of the elements needed to approximate the + * SAX 2.0 standard for Attributes. The implementation is simpler here, + * and not all interfaces are supported. However, the functions match + * the Attributes interface from the specification + */ + +namespace xml +{ +namespace lite +{ +/*! + * \class AttributeNode + * \brief An internal holding structure for Attributes. + * + * This provides the definition of an Attribute's + * internal organs. We have a URI, a QName, and a local part + * as well. We also need a value, of course. + */ +class AttributeNode +{ +public: + + //! Constructor + AttributeNode() + { + } + + /*! + * Copy constructor + * \param attributeNode + * Copy attribute node to *this + */ + AttributeNode(const AttributeNode & attributeNode); + + /*! + * Assignment operator + * \param attributeNode + * Copy attribute node to *this + */ + AttributeNode& operator=(const AttributeNode& attributeNode); + + //! Destructor + ~AttributeNode() + { + } + + /*! + * This function takes a fully qualified name. + * It does not allow for a URI. use setUri() to + * bind a namespace + * \param qname The fully qualified name + */ + void setQName(const std::string& qname); + + /*! + * Set the local (unqualified portion) of the name + * \param lname The new local name + * + */ + void setLocalName(const std::string& lname); + + /*! + * Set the prefix (qualified portion) of the name + * \param prefix This is the prefix + */ + void setPrefix(const std::string& prefix); + + /*! + * Set the URI association in the QName + * \param uri The new uri + */ + void setUri(const std::string& uri); + + /*! + * Set the attribute value + * \param value The attribute value + */ + void setValue(const std::string& value); + + /*! + * Get the URI associated with the QName. Blank string + * if none. + * \return The uri + */ + std::string getUri() const; + std::string getLocalName() const; + std::string getPrefix() const; + std::string getValue() const; + std::string& getValue() + { + return mValue; + } + std::string getQName() const; + +protected: + + QName mName; + //! The value of the attribute + std::string mValue; + +}; + +/*! + * \class Attributes + * \brief This class handles the attribute components. + * + * The DOM and SAX specifications are very different, + * but their difference is what makes the implementations so + * onerous. Here, we simplify the interface so that it dom and + * sax are essentially sharing the same components. The dom + * model is built on the sax model, allowing us to make use of + * this data structure everywhere. That also allows us to + * simplify future dom classes + */ +class Attributes +{ +public: + + typedef std::vector Attributes_T; + //! Default constructor + Attributes() + { + } + + //! Copy constructor + Attributes(const Attributes & attributes); + + //! Assignment operator + Attributes & operator=(const Attributes & attributes); + + //! Destructor + ~Attributes() + { + } + + /*! + * Adds an attribute to the list of attributes. + * \param attribute the attribute to add + */ + void add(const AttributeNode & attribute); + + /*! + * Look up the index of an attribute by XML 1.0 qualified name. + * \param qname The fully qualified name of the attribute + * \return the index or -1 if none found + */ + int getIndex(const std::string & qname) const; + + /*! + * Look up the index of an attribute by Namespace name. + * \param uri The uri association + * \param localName The local name of the attribute + * \return the index or -1 if none found + */ + int getIndex(const std::string & uri, const std::string & localName) const; + + /*! + * Return the number of attributes in the list. + * \return The number of attributes contained herein + */ + int getLength() const + { + return (int) mAttributes.size(); + } + + /*! + * Look up an attribute's local name by index. + * \param i The index of the attribute + * \return The local name of the attribute + * \throw IndexOutOfRangeException if the index is out of range + */ + std::string getLocalName(int i) const; + + std::string getQName(int i) const; + + /*! + * Look up an attribute's Namespace URI by index. + * \param i The index for the attribute we want + * \return the uri for our attribute + * \throw IndexOutOfRangeException if the index is out of range + */ + std::string getUri(int i) const; + + /*! + * Look up an attribute's value by index. + * \param i The index for the attribute we want + * \return the value of the attribute + * \throw IndexOutOfRangeException if the index is out of range + */ + std::string getValue(int i) const; + + /*! + * Look up an attribute's value by XML 1.0 qualified name. + * \param qname The qualified name + * \return The value + * \throw NoSuchKeyException If the qname is not found + */ + std::string getValue(const std::string & qname) const; + + /*! + * Look up an attribute's value by Namespace name. + * \param uri The uri association + * \param localName the local name of the object + * \return The value + * \throw NoSuchKeyException If the qname is not found + */ + std::string getValue(const std::string & uri, + const std::string & localName) const; + /*! + * Get an attribute note based on the index as a const ref + * \param i The node index + * \return The attribute node + */ + const AttributeNode& getNode(int i) const; + + /*! + * Get an attribute note based on the index as a non-const ref + * \param i The node index + * \return The attribute node + */ + AttributeNode& getNode(int i); + + /*! + * Get an attribute note based on the index as a const ref + * \param i The node index + * \return The attribute node + */ + + const AttributeNode& operator[](int i) const + { + return getNode(i); + } + + std::string& operator[](std::string s) + { + int idx = getIndex(s); + if (idx < 0) + { + AttributeNode node; + node.setQName(s); + mAttributes.push_back(node); + idx = (int)(mAttributes.size() - 1); + } + return mAttributes[(size_t)idx].getValue(); + } + + /*! + * Get an attribute note based on the index as a non-const ref + * \param i The node index + * \return The attribute node + */ + AttributeNode& operator[](int i) + { + return getNode(i); + } + + /** + * Remove the attribute with the given QName + */ + void remove(const std::string& qname) + { + int idx = getIndex(qname); + if (idx >= 0) + remove((size_t)idx); + } + + bool contains(const std::string& qname) const + { + try + { + getValue(qname); + return true; + } + catch(const except::NoSuchKeyException&) + { + return false; + } + } + + /** + * Remove the attribute at the given index (if possible) + */ + void remove(size_t index) + { + if (index < mAttributes.size()) + { + Attributes_T::iterator it = mAttributes.begin(); + for(size_t i = 0; i < index; ++i, ++it); + mAttributes.erase(it); + } + } + + void clear() + { + mAttributes.clear(); + } +private: + //! Underlying representation + Attributes_T mAttributes; +}; +} +} + +#endif diff --git a/modules/c++/xml.lite/include/xml/lite/ContentHandler.h b/modules/c++/xml.lite/include/xml/lite/ContentHandler.h new file mode 100644 index 000000000..967e2581b --- /dev/null +++ b/modules/c++/xml.lite/include/xml/lite/ContentHandler.h @@ -0,0 +1,126 @@ +/* ========================================================================= + * This file is part of xml.lite-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2011, General Dynamics - Advanced Information Systems + * + * xml.lite-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __XML_LITE_CONTENT_HANDLER_H__ +#define __XML_LITE_CONTENT_HANDLER_H__ + +#include +#include "xml/lite/Attributes.h" + +/*! + * \file ContentHandler.h + * \brief Implementation of a SAX 2.0 content handler + * + * Contains the implementation of the SAX 2.0 content handler. A "content + * handler" is the processing class for an XML reader. To do any XML + * processing, you simply redefine (parts of) the ContentHandler to + * suit your needs. + */ + +namespace xml +{ +namespace lite +{ +/*! + * \class ContentHandler + * \brief The handler for SAX 2.0 + * \todo Implement start/endPrefixMapping + * + * A SAX reader requires a processing unit known as the + * "content handler." Contained herein is the implementation for + * a simple one. Unlike the SAX specification, we dont separate the + * ContentHandler (which is an interface in SAX) from the + * DefaultContentHandler. This lowers package complexity, + * and leaves us with a practical base from which to inherit. + * Any functionality that we dont add is not pure virtual, but is + * an empty function call. + * + * This saves the trouble of having to redefine every interface + * method, allowing the developer to focus only on the routines + * which he or she is interested in defining. + * It also leaves us with less virtual classes hanging around, + * which should increase performance and efficiency. + */ + +class ContentHandler +{ +public: + //! Constructor + ContentHandler() + { + } + + //! Destructor + virtual ~ContentHandler() + { + } + + //! Receive notification of the beginning of a document. + virtual void startDocument() + { + } + //! Receive notification of the end of a document. + virtual void endDocument() + { + } + + /*! + * Receive notification of character data. + * Fired when we get character data + * \param data The character data + * \param length The length of the new data + */ + virtual void characters(const char *data, int length) = 0; + + /*! + * Receive notification of the beginning of an element. + * \param uri The associated uri + * \param localName The local name of the element + * \param qname the qualified name + * \param attributes The attributes for this element + */ + virtual void startElement(const std::string & uri, + const std::string & localName, + const std::string & qname, + const xml::lite::Attributes & attributes) = 0; + /*! + * Receive notification of the end of an element. + * \param uri The associated uri + * \param localName The local name of the element + * \param qname the qualified name + */ + virtual void endElement(const std::string & uri, + const std::string & localName, + const std::string & qname) = 0; + + /*! + * This isnt in SAX 2.0, but I think it might be useful + * \param c The comment + */ + virtual void comment(const std::string & c) + { + } +}; +} +} + +#endif diff --git a/modules/c++/xml.lite/include/xml/lite/Document.h b/modules/c++/xml.lite/include/xml/lite/Document.h new file mode 100644 index 000000000..ae96d899e --- /dev/null +++ b/modules/c++/xml.lite/include/xml/lite/Document.h @@ -0,0 +1,156 @@ +/* ========================================================================= + * This file is part of xml.lite-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2011, General Dynamics - Advanced Information Systems + * + * xml.lite-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __XML_LITE_DOM_DOCUMENT_H__ +#define __XML_LITE_DOM_DOCUMENT_H__ + +/*! + * \file Document.h + * \brief File describing the tree API + * + * This is a simple alternative to the DOM API. It is very similar, + * but is a solution intended more for speed and simplicity. The + * DOM API offers far more functionality, where this version implements + * only the widely used features. In this file, we are only concerned + * with the data structure for implementing the XML reader, not the reader + * itself. + */ + +#include "xml/lite/Element.h" + +namespace xml +{ +namespace lite +{ +/*! + * \class Document + * \brief This class is the organizer for a tree of elements. + * + * Use the Document to access the Element nodes contained within. + * The DocumentParser will build a tree that you can use. + */ +class Document +{ +public: + //! Constructor + Document(Element* rootNode = NULL, bool own = true) : + mRootNode(rootNode), mOwnRoot(own) + { + } + + /*! + * Destroy the xml tree. This deletes the nodes if they exist + * Careful, this may delete your copy if you are not careful + */ + virtual ~Document() + { + destroy(); + } + + virtual Document* clone() const + { + Document* doc = new Document(); + + Element* cloneRoot = new Element(); + cloneRoot->clone(*mRootNode); + doc->setRootElement(cloneRoot); + return doc; + } + + /*! + * Factory-type method for creating a new Element + * \param qname The qname of the new element + * \param uri The URI of the new element + * \param characterData The character data (if any) + * \return A new element + */ + virtual Element *createElement(const std::string & qname, + const std::string & uri, + std::string characterData = ""); + + /*! + * Blanket destructor. This thing deletes everything + */ + void destroy(); + + /*! + * Insert an element under this element. Secretly, this + * tree does not really care whether or not the element in + * question is added to this tree or another tree, or just + * an element. It simply connects the two items + * \param element Element to add + * \param underThis Element to add element to + */ + virtual void insert(Element * element, Element * underThis); + + /*! + * Remove an element from the tree, starting at the root + * \param toDelete The node to delete (This DOES do deletion) + */ + virtual void remove(Element * toDelete); + + /*! + * Remove an element from the tree, starting at the second param + * \param toDelete The node to delete (This DOES do deletion) + * \param fromHere The place to start looking for. This could + * be an optimization depending on the task, so I allow it to remain + * public + */ + virtual void remove(Element * toDelete, Element * fromHere); + + /*! + * Sets the internal root element + * \param element The node to set. + */ + void setRootElement(Element * element, bool own = true); + + /*! + * Retrieves the internal root element + * \return The root node + */ + Element *getRootElement(bool steal = false) + { + if (steal) + mOwnRoot = false; + return mRootNode; + } + + Element *getRootElement() const + { + return mRootNode; + } + +protected: + //! Copy constructor + Document(const Document&); + + //! Assignment operator + Document& operator=(const Document&); + + //! The root node element + Element *mRootNode; + bool mOwnRoot; +}; +} +} + +#endif diff --git a/modules/c++/xml.lite/include/xml/lite/Element.h b/modules/c++/xml.lite/include/xml/lite/Element.h new file mode 100644 index 000000000..a96c397ff --- /dev/null +++ b/modules/c++/xml.lite/include/xml/lite/Element.h @@ -0,0 +1,354 @@ +/* ========================================================================= + * This file is part of xml.lite-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * xml.lite-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __XML_LITE_ELEMENT_H__ +#define __XML_LITE_ELEMENT_H__ + +#include +#include +#include "xml/lite/XMLException.h" +#include "xml/lite/Attributes.h" + +/*! + * \file Element.h + * \brief This contains the xml::lite data type for elements. + * + * This class is analogous to its DOM namesake. It contains all of + * the information that would be expected of it, including comment data. + * The API, however, is much simpler and less developed than DOM. + */ + +// xml::lite::Element +namespace xml +{ +namespace lite +{ +/*! + * \class Element + * \brief The class defining one element of an XML document + * + * This class stores all of the element information about an XML + * document. + */ +class Element +{ +public: + //! Default constructor + Element() : + mParent(NULL) + { + } + + /*! + * Constructor taking the namespace prefix and the local name + * \param qname The qname of the object + * \param uri The uri of the object + * \param characterData The character data (if any) + */ + Element(const std::string& qname, const std::string& uri = "", + std::string characterData = "") : + mParent(NULL), mName(uri, qname), mCharacterData(characterData) + { + } + + //! Destructor + virtual ~Element() + { + destroyChildren(); + } + + //! Destroys any child elements. + void destroyChildren(); + + /*! + * Copy constructor + * \param element Takes an element + */ + Element(const Element& element); + + /*! + * Assignment operator + * \param element Takes an element + * \return a reference to *this + */ + Element& operator=(const Element& element); + + /*! + * Clone function performs deep copy + * of element + * \param element Takes an element + */ + void clone(const Element& element); + + /*! + * Get the attributes in a non-const way + * \return attributes + */ + Attributes& getAttributes() + { + return mAttributes; + } + + std::string& attribute(std::string s) + { + return mAttributes[s]; + } + + /*! + * Get the attributes in a const way + * \return attributes + */ + const Attributes& getAttributes() const + { + return mAttributes; + } + + /*! + * Set the attributes + * \param attributes The attributes to set + */ + void setAttributes(const Attributes& attributes) + { + mAttributes.clear(); + for (int i = 0; i < attributes.getLength(); i++) + { + mAttributes.add(attributes.getNode(i)); + } + } + + /*! + * Get the elements by tag name + * \param qname the QName + * \param elements the elements that match the QName + */ + void getElementsByTagNameNS(const std::string& qname, + std::vector& elements, + bool recurse = false) const; + + /*! + * Utility for people that dont like to pass by reference + * + */ + std::vector getElementsByTagNameNS(const std::string& qname, + bool recurse = false) const + { + std::vector v; + getElementsByTagNameNS(qname, v, recurse); + return v; + } + + /*! + * Sometimes we dont care about the qname or the uri -- just + * the local name is good enough. For those times, use this function + * \param localName The local name + * \param elements The elements + */ + void getElementsByTagName(const std::string& localName, + std::vector& elements, + bool recurse = false) const; + + /*! + * Utility for people that dont like to pass by reference + */ + std::vector getElementsByTagName(const std::string& localName, + bool recurse = false) const + { + std::vector v; + getElementsByTagName(localName, v, recurse); + return v; + } + + /*! + * Get the elements by tag name + * \param uri the URI + * \param localName the local name + * \param elements the elements that match the QName + */ + void getElementsByTagName(const std::string& uri, + const std::string& localName, + std::vector& elements, + bool recurse = false) const; + + /*! + * 1) Find this child's attribute and change it + * 2) Recursively descend over children and fix all + * namespaces below using fixNodeNamespace() + */ + void setNamespacePrefix(std::string prefix, std::string uri); + + void setNamespaceURI(std::string prefix, std::string uri); + + /*! + * Prints the element to the specified OutputStream + * \param stream the OutputStream to write to + * \param formatter The formatter + * \todo Add format capability + */ + void print(io::OutputStream& stream) const; + + void prettyPrint(io::OutputStream& stream, + std::string formatter = " ") const; + + /*! + * Determines if a child element exists + * \param localName the local name to search for + * \return true if it exists, false if not + */ + bool hasElement(const std::string& localName) const; + + /*! + * Determines if a child element exists + * \param uri the URI to search for + * \param localName the local name to search for + * \return true if it exists, false if not + */ + bool hasElement(const std::string& uri, + const std::string& localName) const; + + /*! + * Returns the character data of this element. + * \return the charater data + */ + std::string getCharacterData() const + { + return mCharacterData; + } + + /*! + * Sets the character data for this element. + * \param characters The data to add to this element + */ + void setCharacterData(const std::string& characters) + { + mCharacterData = characters; + } + + /*! + * Sets the local name for this element. + * \param localName the data to add to this element + */ + void setLocalName(const std::string& localName) + { + mName.setName(localName); + } + + /*! + * Returns the local name of this element. + * \return the local name + */ + std::string getLocalName() const + { + return mName.getName(); + } + + /*! + * Sets the QName for this element. + * \param qname the data to add to this element + */ + void setQName(const std::string& qname) + { + mName.setQName(qname); + } + + /*! + * Returns the QName of this element. + * \return the QName + */ + std::string getQName() const + { + return mName.toString(); + } + + /*! + * Sets the URI for this element. + * \param uri the data to add to this element + */ + void setUri(const std::string& uri) + { + mName.setAssociatedUri(uri); + } + + /*! + * Returns the URI of this element. + * \return the URI + */ + std::string getUri() const + { + return mName.getAssociatedUri(); + } + + /*! + * Adds a child element to this element + * \param node the child element to add + */ + virtual void addChild(Element * node); + + /*! + * Returns all of the children of this element + * \return the children of this element + */ + std::vector& getChildren() + { + return mChildren; + } + + /*! + * Returns all of the children of this element + * \return the children of this element + */ + const std::vector& getChildren() const + { + return mChildren; + } + + Element* getParent() const + { + return mParent; + } + + void setParent(Element* parent) + { + mParent = parent; + } + +protected: + + void changePrefix(Element* element, std::string prefix, std::string uri); + + void changeURI(Element* element, std::string prefix, std::string uri); + + void depthPrint(io::OutputStream& stream, int depth, + std::string formatter) const; + + Element* mParent; + //! The children of this element + std::vector mChildren; + xml::lite::QName mName; + //! The attributes for this element + xml::lite::Attributes mAttributes; + //! The character data + std::string mCharacterData; +}; +} +} + +#endif diff --git a/modules/c++/xml.lite/include/xml/lite/MinidomHandler.h b/modules/c++/xml.lite/include/xml/lite/MinidomHandler.h new file mode 100644 index 000000000..0eca4dff9 --- /dev/null +++ b/modules/c++/xml.lite/include/xml/lite/MinidomHandler.h @@ -0,0 +1,170 @@ +/* ========================================================================= + * This file is part of xml.lite-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * xml.lite-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __XML_LITE_MINIDOM_HANDLER_H__ +#define __XML_LITE_MINIDOM_HANDLER_H__ + +/*! + * \file MinidomHandler.h + * \brief A fast, small, alternative to DOM. + * + * This handler inherits a ContentHandler, and loads all components + * into a more simple and logical tree structure. Whereas, in DOM, + * EVERYTHING is a node, here, the hierarchical approach is used. + * An element is a tagset (i.e., <blah att1="hello">hi I'm dan</blah>, + * and embedded tags are children. To walk the tree, get the top- + * level element and walk it. + * + * There is memory allocation in this file, however, the paradigm is + * that since it occurs internally, it should be deleted internally + * as well. Thus, when the Document goes out of scope (i.e., the destructor + * is called), it will delete its element nodes. This makes sense if you + * consider that, without the parser, there is no tree. So, let the + * parser handle its own business. + * + * \todo Add iterators + */ + +#include +#include "XMLReader.h" +#include "io/StandardStreams.h" +#include "io/DbgStream.h" +#include "Document.h" + +namespace xml +{ +namespace lite +{ +/*! + * \class MinidomHandler + * \brief This class is an XML reader that fills a tree. + * + * The class has a tree that it populates with XML data as + * it parses, The Document* is owned by this class, no matter, + * whether it is allocated externally or not. DONT delete it + * explicitly unless you are looking for disaster. + */ +class MinidomHandler : public ContentHandler +{ +public: + //! Constructor. Uses default document + MinidomHandler() : + mDocument(NULL), mOwnDocument(true), mPreserveCharData(false) + { + setDocument(new Document()); + } + + //! Destructor + virtual ~ MinidomHandler() + { + setDocument(NULL, true); + } + + virtual void setDocument(Document *newDocument, bool own = true); + + /** + * Retrieves the Document. + * @param steal if specified, ownership will be given up (if owned) + */ + virtual Document *getDocument(bool steal = false) + { + if (steal) + mOwnDocument = false; + return mDocument; + } + + virtual Document *getDocument() const + { + return mDocument; + } + + /*! + * This is the function overload for handling char data. + * We append the chunk to the current data, and add the + * length to the top of the bytes stack. + * \param value The value of the char data + * \param length The length of the char data + */ + virtual void characters(const char *value, int length); + + /*! + * This method is fired when a new tag is entered. + * We use our newElement() method to spawn a new + * element and we set its tag to our tag param and its attributes + * to our atts param. We then push it on the node stack, + * and we reset the char data byte count stack for this new object + * \param uri The uri + * \param localName The local name + * \param qname The qname + * \param atts The attributes + */ + virtual void startElement(const std::string & uri, + const std::string & localName, + const std::string & qname, + const Attributes & atts); + + /*! + * We want to push only the proper amount of bytes + * to the node when we start writing. Here we chew + * up the pieces we take as we are taking them. + * \return The chracter data for the node + */ + virtual std::string adjustCharacterData(); + + /*! + * Handles the actual popping of the node off the node + * stack, and the adjustment of that node's character data. + * Here we add the node to the tree + * \param uri The uri + * \param localName The local name + * \param qname The qname + */ + virtual void endElement(const std::string & uri, + const std::string & localName, + const std::string & qname); + + virtual void clear(); + + /*! + * Trim the white space off the back and front of a string + * \param s String to trim + */ + static void trim(std::string & s); + + /*! + * If set to true, whitespaces will be preserved in the parsed + * character data. Otherwise, it will be trimmed. + */ + virtual void preserveCharacterData(bool preserve); + +protected: + std::string currentCharacterData; + std::stack bytesForElement; + std::stack nodeStack; + Document *mDocument; + bool mOwnDocument; + bool mPreserveCharData; +}; +} +} + +#endif diff --git a/modules/c++/xml.lite/include/xml/lite/MinidomParser.h b/modules/c++/xml.lite/include/xml/lite/MinidomParser.h new file mode 100644 index 000000000..22f39b91c --- /dev/null +++ b/modules/c++/xml.lite/include/xml/lite/MinidomParser.h @@ -0,0 +1,133 @@ +/* ========================================================================= + * This file is part of xml.lite-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2011, General Dynamics - Advanced Information Systems + * + * xml.lite-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __XML_LITE_MINIDOM_PARSER_H__ +#define __XML_LITE_MINIDOM_PARSER_H__ + +#include "xml/lite/XMLReader.h" +#include "xml/lite/Document.h" +#include "xml/lite/Element.h" +#include "xml/lite/MinidomHandler.h" + +/*! + * \file MinidomParser.h + * \brief This is the API for the minidom parser. + * + * The MinidomParser class is a simple DOM parser. Much of the DOM + * functionality is not present, however, it is sufficient for simple + * SOAP/WSDL parsing, etc. The idea is that a parser has a content handler, + * and a SAX driver underneath, and that we can switch element types by + * overloading the underlying Document class, and binding the document class + * in the handler to our new class. + */ + +namespace xml +{ +namespace lite +{ +/*! + * \class MinidomParser + * \brief Almost painfully simple DOM parser. + * + * This class provides a simple, quick DOM parser, with none of the + * bloat of the spec. It was inspired by python's xml.dom.minidom + * module. + */ +class MinidomParser +{ +public: + /*! + * Constructor. Set our SAX ContentHandler. + */ + MinidomParser(); + + //! Destructor. + virtual ~MinidomParser() + { + } + + /*! + * Present our parsing interface. Similar to DOM, the input + * is an InputStream (DOM's is called input source), but it + * is even more flexible, and works within the XPC io paradigm. + * \param is This is the input stream to feed the parser + * \param size This is the size of the stream to feed the parser + */ + virtual void parse(io::InputStream& is, int size = io::InputStream::IS_END); + + + /*! + * This clears the MinidomHandler, killing its underlying Document + * tree. The Document node is preserved, however -- it must + * be explicitly reset to another document to change element type. + */ + virtual void clear(); + + /*! + * Return a pointer to the document. Note that its a reference + * so you dont get to keep it. + * \return Pointer to document. + */ + virtual Document *getDocument() const; + + virtual Document *getDocument(bool steal = false); + + /*! + * Reader accessor + * \return The reader by constant reference + */ + const XMLReader& getReader() const + { + return mReader; + } + + /*! + * Reader accessor + * \return The reader by reference + */ + XMLReader& getReader() + { + return mReader; + } + + /*! + * This is the public interface for resetting the + * XML document. This will call the handler version of this + * function, which will delete the old document. + * + * \param newDocument The new document. + */ + virtual void setDocument(Document * newDocument, bool own = true); + + /*! + * @see MinidomHandler::preserveCharacterData + */ + virtual void preserveCharacterData(bool preserve); + +protected: + MinidomHandler mHandler; + XMLReader mReader; +}; +} +} + +#endif diff --git a/modules/c++/xml.lite/include/xml/lite/NamespaceStack.h b/modules/c++/xml.lite/include/xml/lite/NamespaceStack.h new file mode 100644 index 000000000..b6405c37e --- /dev/null +++ b/modules/c++/xml.lite/include/xml/lite/NamespaceStack.h @@ -0,0 +1,134 @@ +/* ========================================================================= + * This file is part of xml.lite-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * xml.lite-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __XML_LITE_NAMESPACE_STACK_H__ +#define __XML_LITE_NAMESPACE_STACK_H__ + +/*! + * \file NamespaceStack.h + * \brief An implementation of a scope-based namespace mapper + * + * Namespaces arent very useful if there is no way to resolve them + * using their respective components. Unfortunately, the solution + * is more complex than would be expected. Here are the rules: + * 1) We are out of scope if the xmlns mapping takes place inside a + * sub-element (it must be declared in this element or a parent. + * + * 2) Prefixes MUST be unique at least in scope. + * For example, xmlns:x = "blah" and then + * another mapping over it xmlns:x="blah2" is ok. blah2 is in local scope, + * and blah is in global scope, which means, when we pop x off the first + * time, the initial x remains. + * + * 3) URI's MAY be duplicate. For example: + * xmlns:x="a-uri" and xmlns:y="a-uri" are both valid at the same time + * + * We guarantee this with a namespace stack. + * + */ + +#include +#include +#include +#include +#include "except/Exception.h" + +namespace xml +{ +namespace lite +{ +typedef std::stack NamespaceRefStack; +typedef std::pair NamespaceEntity; +typedef std::vector NamespaceEntityMap; + +/*! + * \class NamespaceStack + * \brief A namespace mapping object + * This object uses scope declarator functions push and pop to + * determine when to add and throw away entities. Internally, + * it uses a stack of range-marker integers, which represent + * how many elements where added for each new scope. + * + * + */ +class NamespaceStack +{ +public: + NamespaceStack() + { + } + + ~NamespaceStack() + { + } + + /*! + * Push a new scope on the stack. This will add a zero- + * initialized integer to the reference stack. + * The XMLReader caller will use at the beginning of the + * startElement() method. + */ + void push(); + + /*! + * Pop the scope off the stack. This will pop the integer + * off the reference stack and delete the value number of + * namespaces off of the namespace mapping stack. + * It should be called in the XMLReader in the endElement() + * method. + */ + void pop(); + + /*! + * Create a scope-based association between the prefix + * and the uri in question. The top of the reference stack + * will be incremented, and the mapping will be established + * in the namespace mapping stack + * \param prefix The unique prefix to associate + * \param uri The uri to associate + */ + void newMapping(const std::string & prefix, const std::string & uri); + + /*! + * Of course, we also wish to retrieve the + * mapping from the namespace stack. + * \param prefix The unique prefix to retrieve our uri for + * \return The associated uri or "" if none is available + */ + std::string getMapping(const std::string & prefix) const; + + /*! + * Get back an array of all of the prefixes in our namespace + * stack + * \param allPrefixes All of the prefixes + * + */ + void getAllPrefixes(std::vector &allPrefixes) const; + +private: + NamespaceEntityMap mMappingStack; + NamespaceRefStack mRefStack; +}; +} +} + +#endif diff --git a/modules/c++/xml.lite/include/xml/lite/QName.h b/modules/c++/xml.lite/include/xml/lite/QName.h new file mode 100644 index 000000000..ff8328576 --- /dev/null +++ b/modules/c++/xml.lite/include/xml/lite/QName.h @@ -0,0 +1,179 @@ +/* ========================================================================= + * This file is part of xml.lite-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * xml.lite-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __XML_LITE_QNAME_H__ +#define __XML_LITE_QNAME_H__ + +/*! + * \file QName.h + * \brief A Qualified name (includes the namespace stuff) + * + * When XML started, the notion of a namespace was rarely used (and + * many of us were happier that way). Namespaces add complexity, but + * the also allow for name resolution in a non-conflicting manner. + * Unfortunately, the XML SAX readers, the event-driven parsers people + * tend to use, at least as underlying structures have become more complex. + * At any rate, a qualified name consists of 1) the local part (that is + * the portion people used to use alone, without any namespace, and 2) + * the prefix for the namespace, which presumably maps to a namespace URI + * + */ + +#include + +namespace xml +{ + +namespace lite +{ +/*! + * \class QName + * \brief A Qualified name (includes the namespace stuff) + * + * When XML started, the notion of a namespace was rarely used (and + * many of us were happier that way). Namespaces add complexity, but + * the also allow for name resolution in a non-conflicting manner. + * Unfortunately, the XML SAX readers, the event-driven parsers people + * tend to use, at least as underlying structures have become more + * complex. At any rate, a qualified name consists of + * 1) the local part (that is the portion people used to use alone, + * without any namespace, and + * 2) the prefix for the namespace, which presumably maps + * to a namespace URI + */ + +class QName +{ +public: + //! Default constructor + QName() + { + } + + /*! + * Constructor taking the namespace prefix and the local name + * \param uri The uri of the object + * \param qname The qname of the object + */ + QName(const std::string& uri, const std::string& qname) + { + setQName(qname); + setAssociatedUri(uri); + } + + /*! + * Constructor taking just the local name (no namespace). + * \param lName Just the local name of the object. + */ + QName(const std::string& lName) + { + setName(lName); + } + + //! Destructor + ~QName() + { + } + + QName(const QName & qname) + { + mPrefix = qname.mPrefix; + mLocalName = qname.mLocalName; + mAssocUri = qname.mAssocUri; + } + + QName& operator=(const QName& qname) + { + if (this != &qname) + { + mPrefix = qname.mPrefix; + mLocalName = qname.mLocalName; + mAssocUri = qname.mAssocUri; + } + return *this; + } + + /*! + * Set the local part (unqualified) + * \param str The local name to set + * + */ + void setName(const std::string& str); + std::string getName() const; + /*! + * If this is a fully-qualified name, set it, + * otherwise, set the local name. + * \param str + */ + void setQName(const std::string& str); + + /*! + * Set the prefix (name preceding colon) + * \param prefix A new prefix + * + */ + void setPrefix(const std::string& prefix); + + /*! + * Get the prefix + * \return The prefix + * + */ + std::string getPrefix() const; + + /*! + * Retrieve the qname as a string. If you have no prefix/uri + * this returns just the local name + * \return The fully qualifed qname (e.g., soap-env:SOAP-BODY) + */ + std::string toString() const; + + /*! + * A QName is nothing without its associated URI. + * Here you specify that URI. + * \param uri The URI to associate with this QName + */ + void setAssociatedUri(const std::string& uri); + + /*! + * Get the URI associated with the QName + * \return The Associated URI + * + */ + std::string getAssociatedUri() const; + +protected: + /* Assignment operator */ + QName& operator=(const std::string& str); + + //! Prefix (Qualified) + std::string mPrefix; + //! Local Part (Unqualified) + std::string mLocalName; + //! Associated URI for Prefix + std::string mAssocUri; + +}; +} +} + +#endif diff --git a/modules/c++/xml.lite/include/xml/lite/Serializable.h b/modules/c++/xml.lite/include/xml/lite/Serializable.h new file mode 100644 index 000000000..30f02f12a --- /dev/null +++ b/modules/c++/xml.lite/include/xml/lite/Serializable.h @@ -0,0 +1,89 @@ +#ifndef __XML_LITE_SERIALIZABLE_H__ +#define __XML_LITE_SERIALIZABLE_H__ + +#include "io/OutputStream.h" +#include "io/InputStream.h" +#include "io/Serializable.h" +#include "xml/lite/MinidomParser.h" + +/*! + * \file Serializable.h + * \brief Provides the class for creating and processing XML documents + * + * This file contains the serializable class for XML documents + */ +namespace xml +{ +namespace lite +{ +/*! + * \class Serializable + * \brief Document building and processing class + * + * This class provides a Serializable interface for XML documents. + * Internally, it has a parser for XML, and it has a "document" + * containing a tree representation for all of its nodes. Note that + * all nodes in a document are dynamically allocated. They are deleted + * by the class at destruction time. + */ +class Serializable : public io::Serializable +{ +public: + //! Constructor + Serializable() {} + + Serializable(Document* document, bool own = true) + { + setDocument(document, own); + } + + //! Destructor + virtual ~Serializable() {} + + /*! + * Return in the document as it is. Consider throwing null-pointer + * ref upon null. + * \return A Document + */ + virtual Document *getDocument() const + { + return mParser.getDocument(); + } + + virtual Document *getDocument(bool steal = false) + { + return mParser.getDocument(steal); + } + + /*! + * This is the public interface for resetting the + * XML document. This will call the handler version of this + * function, which will delete the old document. + * + * \param newDocument The new document. + */ + void setDocument(Document* document, bool own = true) + { + mParser.setDocument(document, own); + } + + /*! + * Transfer this object into a byte stream + * \param os The object to serialize this to + */ + virtual void serialize(io::OutputStream& os); + + /*! + * Unpack this input stream to the object + * \param is Stream to read object from + */ + virtual void deserialize(io::InputStream& is); + +protected: + //! The parser + ::xml::lite::MinidomParser mParser; +}; +} +} + +#endif diff --git a/modules/c++/xml.lite/include/xml/lite/UtilitiesXerces.h b/modules/c++/xml.lite/include/xml/lite/UtilitiesXerces.h new file mode 100644 index 000000000..2eb476540 --- /dev/null +++ b/modules/c++/xml.lite/include/xml/lite/UtilitiesXerces.h @@ -0,0 +1,442 @@ +/* ========================================================================= + * This file is part of xml.lite-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * xml.lite-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __XML_LITE_UTILITIES_XERCES_H__ +#define __XML_LITE_UTILITIES_XERCES_H__ + +#if defined(USE_XERCES) + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include "xml/lite/XMLException.h" +#include "xml/lite/ContentHandler.h" +#include "xml/lite/Attributes.h" +#include "xml/lite/NamespaceStack.h" +#include "xml/lite/XMLReaderInterface.h" +#include + + +#if defined(XERCES_VERSION_MAJOR) +# if XERCES_VERSION_MAJOR == 2 + typedef unsigned int XercesSize_T; +# else + typedef XMLSize_t XercesSize_T; +# endif +#else + typedef XMLSize_t XercesSize_T; +#endif + + +//XERCES_CPP_NAMESPACE_END +#if defined(XERCES_CPP_NAMESPACE_USE) +XERCES_CPP_NAMESPACE_USE +#endif +typedef ContentHandler XercesContentHandlerInterface_T; +typedef Attributes XercesAttributesInterface_T; +typedef ErrorHandler XercesErrorHandlerInterface_T; + + +namespace xml +{ +namespace lite +{ + + +typedef xml::lite::ContentHandler LiteContentHandler_T; +typedef xml::lite::Attributes LiteAttributes_T; +typedef xml::lite::AttributeNode LiteAttributesNode_T; + +/*! + * Interface to Xerces-C XMLCh*. This is an RAII converter + * between xerces-c 16bit chars to 8bit chars. + * + * This class works off of the assumption that Xerces-c passes + * around pointers as const or non-const depending on the + * ownership limitations of the memory and reacts accordingly. + * This object always accepts the memory internally, but for + * non-const it takes ownership, and for const memory (assumed + * to be owned elsewhere) it makes a deep copy for its own use. + */ +class XercesLocalString +{ +public: + + /*! + * Constructor from XMLCh* + * Takes ownership of the memory and will clean it up + * \param xmlStr An XMLCh* + */ + XercesLocalString(XMLCh* xmlStr); + + /*! + * Constructor from const XMLCh* + * Performs a deep copy of the memory for internal use and cleanup + * \param xmlStr An XMLCh* + */ + XercesLocalString(const XMLCh* xmlStr); + + + /*! + * Constructor from const char* + * \param str A const char* + */ + XercesLocalString(const char* str); + + /*! + * Constructor from std::string + * \param str A std::string* + */ + XercesLocalString(const std::string& str); + + + /*! + * Copy Constructor + * Performs a deep copy of the objects internal memory + * \param rhs the right-hand side operand of the operation + */ + XercesLocalString(const XercesLocalString& rhs); + + //! Destructor + ~XercesLocalString() + { + try + { + destroyXMLCh(&mLocal); + } + catch(...) + { + } + } + + /*! + * Gives back a const XMLCh* + * + * returning it as const is important so other classes + * know its owned by this object + * + * \return a const XMLCh* + */ + const XMLCh* toXMLCh() const + { + return mLocal; + } + + /*! + * Assign from an XMLCh* + * Takes ownership of the memory and will clean it up + * \param xmlStr An XMLCh* + * \return A reference to *this + */ + XercesLocalString& operator=(XMLCh* xmlStr); + + /*! + * Assign from a const XMLCh* + * Performs a deep copy of the memory for internal use and cleanup + * \param xmlStr An XMLCh* + * \return A reference to *this + */ + XercesLocalString& operator=(const XMLCh* xmlStr); + + /*! + * Assign from a XercesLocalString + * Performs a deep copy of the objects internal memory + * \param rhs A XercesLocalString* + * \return A reference to *this + */ + XercesLocalString& operator=(const XercesLocalString& rhs); + + /*! Return a native std::string */ + std::string str() const + { + return toStr(mLocal); + } + + /*! + * Convert from const XMLCh* to std::string + * \param xmlStr an XMLCh* string + * \return a local std::string + */ + static std::string toStr(const XMLCh* xmlStr) + { + char* transcodedStr = XMLString::transcode(xmlStr); + std::string ret = transcodedStr; + destroyChArray(&transcodedStr); + return ret; + } + + static void destroyXMLCh(XMLCh** a) + { + if (a != NULL && *a != NULL) + { + try + { + XMLString::release(a); + *a = NULL; + } + catch (...) + { + throw except::Exception(Ctxt( + "XercesLocalString unsuccessful in destroying memory")); + } + } + } + + static void destroyChArray(char** a) + { + if (a != NULL && *a != NULL) + { + try + { + XMLString::release(a); + *a = NULL; + } + catch (...) + { + throw except::Exception(Ctxt( + "XercesLocalString unsuccessful in destroying memory")); + } + } + } + +private: + + //! The local string + XMLCh* mLocal; +}; + + +/*! + * \class XercesContentHandler + * \brief This class is a mapping between Xerces SAX2.0 and xml.lite + * + * With Expat, a C parser, we had to bind function pointers to + * C subroutines, and use those to drive our xml.lite ContentHandler. + * Here, we are starting with an already SAX2.0 compliant parser, + * so our work is very simple. We want to map the fully compliant + * parser to our subset, in a fashion that allows the xml.lite + * interface to remain constant. + * + * Recall that xml.lite is based on a subset of SAX2.0 and DOM calls. + * Under Expat, we get significant performance and simplicity gains, + * by making the parser start with a defined base handler for + * everything. But having Xerces is beneficial as well, particularly + * if you need more conformance. While Expat is the world's fastest + * XML parser, and should be used wherever possible, Apache has + * possibly the most standards conformant implementation. We want + * to allow (in a performance tradeoff) the possibility for + * Xerces use as well as Expat (and ultimately MSXML as well) + * + */ +class XercesContentHandler : public XercesContentHandlerInterface_T +{ +public: + /*! + * Our constructor will use an underlying LiteContentHandler + * We will only bind to this, not free it. + * \param ch The handler to bind + */ + XercesContentHandler(xml::lite::ContentHandler* ch = NULL) + { + mLiteHandler = ch; + } + + ~XercesContentHandler() + {} + + virtual void ignorableWhitespace(const XMLCh* const chars, + const XercesSize_T length) + {} + virtual void processingInstruction(const XMLCh* const target, + const XMLCh* const data) + {} + virtual void setDocumentLocator(const Locator* const locator) + {} + + /*! + * The great thing about standards compliance is that it + * makes our job easier. Here we just map the inputs for + * Xerces to xml.lite, which is usually just a string conversion + * \param chars The character data + * \param length The length + */ + virtual void characters(const XMLCh* const chars, + const XercesSize_T length); + + /*! + * Fire off the end document notification + */ + virtual void endDocument(); + + /*! + * Map input string types to output string types + * and pass to the xml::lite::ContentHandler + * \param uri The uri for the tag + * \param localName The local (unprefixed name) + * \param qname The fully qualified name + */ + virtual void endElement(const XMLCh* const uri, + const XMLCh* const localName, + const XMLCh* const qname); + + virtual void skippedEntity (const XMLCh* const name) + {} + + //! Fire off the start document notification + virtual void startDocument(); + + /*! + * Map input string types to output string types + * and pass to the xml::lite::ContentHandler. Here + * we transfer the attributes to xml::lite::Attributes. + * \param uri The uri for the tag + * \param localName The local (unprefixed name) + * \param qname The fully qualified name + * \param attrs The attributes in Xerces form + */ + virtual void startElement(const XMLCh* const uri, + const XMLCh* const localName, + const XMLCh* const qname, + const XercesAttributesInterface_T &attrs); + + /*! + * Begin prefix mapping. Transfer string types + * \param prefix The prefix to start mapping + * \param uri The corresponding uri + */ + virtual void startPrefixMapping (const XMLCh* const prefix, + const XMLCh* const uri) + { + } + + /*! + * End prefix mapping. Transfer string types + * \param prefix The prefix to stop mapping + */ + virtual void endPrefixMapping (const XMLCh* const prefix) + { + } + + virtual void + setXMLLiteContentHandler(xml::lite::ContentHandler* handler) + { + mLiteHandler = handler; + } + + virtual xml::lite::ContentHandler* + retrieveXMLLiteContentHandler() + { + return mLiteHandler; + } + +protected: + xml::lite::ContentHandler* mLiteHandler; + +} +; + + +/*! +* /class XercesErrorHandler +* +* The error handler in xml::lite does is essentially non-existant +* (and unneccessary, due to the existance of the notification single). +* Our error handler implementation, then, simply calls the raise, +* and warning macros in the factory. +*/ +class XercesErrorHandler : public XercesErrorHandlerInterface_T +{ +public: + /*! + * Receive notification of a warning. We want to call + * __warning__(message); + * \param exception The exception + */ + virtual void warning(const SAXParseException &exception); + + virtual void error (const SAXParseException &exception); + + virtual void fatalError (const SAXParseException &exception); + + // Useless?? + virtual void resetErrors() {} +}; + +/*! + * \class XercesContext + * \brief This class safely creates and destroys Xerces + */ +class XercesContext +{ +public: + + //! Constructor + XercesContext(); + + //! Destructor + ~XercesContext(); + + void destroy(); + +private: + + static sys::Mutex mMutex; + bool mIsDestroyed; +}; + +} +} + +//! Overloaded output operator for XercesLocalString +std::ostream& operator<<(std::ostream& os, + const xml::lite::XercesLocalString& ls); + + +#endif + +#endif diff --git a/modules/c++/xml.lite/include/xml/lite/Validator.h b/modules/c++/xml.lite/include/xml/lite/Validator.h new file mode 100644 index 000000000..3aa6b5603 --- /dev/null +++ b/modules/c++/xml.lite/include/xml/lite/Validator.h @@ -0,0 +1,61 @@ +/* ========================================================================= + * This file is part of xml.lite-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * xml.lite-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __XML_LITE_VALIDATOR_H__ +#define __XML_LITE_VALIDATOR_H__ + + +#if defined(USE_XERCES) +# include "xml/lite/ValidatorXerces.h" +namespace xml +{ +namespace lite +{ + +typedef ValidatorXerces Validator; +} + +} +#elif defined(USE_LIBXML) +# include "xml/lite/ValidatorLibXML.h" +namespace xml +{ +namespace lite +{ +typedef ValidatorLibXML Validator; +} +} +#else +# if !defined(USE_EXPAT) +# define USE_EXPAT 1 +# endif +# include "xml/lite/ValidatorExpat.h" +namespace xml +{ +namespace lite +{ +typedef ValidatorExpat Validator; +} +} +#endif + +#endif diff --git a/modules/c++/xml.lite/include/xml/lite/ValidatorExpat.h b/modules/c++/xml.lite/include/xml/lite/ValidatorExpat.h new file mode 100644 index 000000000..613dc7638 --- /dev/null +++ b/modules/c++/xml.lite/include/xml/lite/ValidatorExpat.h @@ -0,0 +1,85 @@ +/* ========================================================================= + * This file is part of xml.lite-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2011, General Dynamics - Advanced Information Systems + * + * xml.lite-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __XML_LITE_VALIDATOR_EXPAT_H__ +#define __XML_LITE_VALIDATOR_EXPAT_H__ + +#ifdef USE_EXPAT + +#include +#include + +namespace xml +{ +namespace lite +{ + +/*! + * \class ValidatorExpat + * \brief Schema validation is done here. + * + * This class is the Expat schema validator + */ +class ValidatorExpat : public ValidatorInterface +{ +public: + + /*! + * Constructor + * \param schemaPaths Vector of both paths and singular schemas + * Note: All schemas must end in *.xsd + * \param log Logger for reporting errors + * \param recursive Do a recursive search for schemas on directory + * input + */ + ValidatorExpat(const std::vector& schemaPaths, + logging::Logger* log, + bool recursive = true) : + ValidatorInterface(schemaPaths, log, recursive) + { + throw except::Exception(Ctxt( + "Expat does not support Schema Validation")); + } + + using ValidatorInterface::validate; + + /*! + * Validation against the internal schema pool + * \param xml The xml document string to validate + * \param xmlID Identifier for this input xml within the error log + * \param errors Object for returning errors found (errors are appended) + */ + virtual bool validate(const std::string& xml, + const std::string& xmlID, + std::vector& errors) const + { + throw except::Exception(Ctxt( + "Expat does not support Schema Validation")); + } + +}; +} +} + +#endif + +#endif diff --git a/modules/c++/xml.lite/include/xml/lite/ValidatorInterface.h b/modules/c++/xml.lite/include/xml/lite/ValidatorInterface.h new file mode 100644 index 000000000..5002775e7 --- /dev/null +++ b/modules/c++/xml.lite/include/xml/lite/ValidatorInterface.h @@ -0,0 +1,174 @@ +/* ========================================================================= + * This file is part of xml.lite-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2011, General Dynamics - Advanced Information Systems + * + * xml.lite-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __XML_LITE_VALIDATOR_INTERFACE_H__ +#define __XML_LITE_VALIDATOR_INTERFACE_H__ + +/*! + * \file ValidatorInterface.h + * \brief This is the API for the validator interface. + * + * This object is the holder of a pool of schemas in memory + * and gives the ability to validate any xml against this + * pool. + */ + +#include +#include +#include +#include +#include +#include + +namespace xml +{ +namespace lite +{ + +/*! + * \class ValidationInfo + * \brief This is the information for one + * schema validation error. + */ +class ValidationInfo +{ +public: + ValidationInfo(const std::string& message, + const std::string& level, + const std::string& file, + size_t line) : + mMessage(message), mLevel(level), + mFile(file), mLine(line) + { + } + + std::string getMessage() const { return mMessage; } + std::string getLevel() const { return mLevel; } + std::string getFile() const { return mFile; } + size_t getLine() const { return mLine; } + + //! stream to a string + std::string toString() const + { + std::ostringstream oss; + oss << "[" << this->getLevel() << "]" << + " from File: " << this->getFile() << + " on Line: " << str::toString(this->getLine()) << + " with Message: " << this->getMessage(); + return oss.str(); + } + +private: + std::string mMessage; + std::string mLevel; + std::string mFile; + size_t mLine; +}; + +/*! + * \class ValidatorInterface + * \brief Schema validation is done here. + * + * This class is the interface for schema validators + */ +class ValidatorInterface +{ +public: + + enum ValidationErrorType + { + VALIDATION_WARNING = 0, + VALIDATION_ERROR, + VALIDATION_FATAL + }; + + /*! + * Constructor + * \param schemaPaths Vector of both paths and singular schemas + * Note: All schemas must end in *.xsd + * \param log Logger for reporting errors + * \param recursive Do a recursive search for schemas on directory + * input + */ + ValidatorInterface(const std::vector& schemaPaths, + logging::Logger* log, + bool recursive = true) {} + + //! Destructor. + virtual ~ValidatorInterface() {} + + /*! + * Validation against the internal schema pool + * \param xml Input stream to the xml document to validate + * \param xmlID Identifier for this input xml within the error log + * \param errors Object for returning errors found (errors are appended) + */ + bool validate(io::InputStream& xml, + const std::string& xmlID, + std::vector& errors) const + { + // convert to std::string + io::ByteStream bs; + xml.streamTo(bs); + return validate(bs.stream().str(), xmlID, errors); + } + + /*! + * Validation against the internal schema pool + * \param xml Input stream to the xml document to validate + * \param xmlID Identifier for this input xml within the error log + * \param errors Object for returning errors found (errors are appended) + */ + bool validate(const Element* xml, + const std::string& xmlID, + std::vector& errors) const + { + // convert to stream + io::ByteStream bs; + xml->print(bs); + return validate(bs.stream().str(), xmlID, errors); + } + + + /*! + * Validation against the internal schema pool + * \param xml The xml document string to validate + * \param xmlID Identifier for this input xml within the error log + * \param errors Object for returning errors found (errors are appended) + */ + virtual bool validate(const std::string& xml, + const std::string& xmlID, + std::vector& errors) const = 0; + +}; +} +} + +inline std::ostream& operator<< ( + std::ostream& out, + const xml::lite::ValidationInfo& info) +{ + out << info.toString(); + return out; +} + +#endif diff --git a/modules/c++/xml.lite/include/xml/lite/ValidatorLibXML.h b/modules/c++/xml.lite/include/xml/lite/ValidatorLibXML.h new file mode 100644 index 000000000..2fbc3a0c6 --- /dev/null +++ b/modules/c++/xml.lite/include/xml/lite/ValidatorLibXML.h @@ -0,0 +1,84 @@ +/* ========================================================================= + * This file is part of xml.lite-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2011, General Dynamics - Advanced Information Systems + * + * xml.lite-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __XML_LITE_VALIDATOR_LIBXML_H__ +#define __XML_LITE_VALIDATOR_LIBXML_H__ + +#ifdef USE_LIBXML + +#include +#include + +namespace xml +{ +namespace lite +{ + +/*! + * \class ValidatorLibXML + * \brief Schema validation is done here. + * + * This class is the LibXML schema validator + * TODO: Implement this solution + */ +class ValidatorLibXML : public ValidatorInterface +{ +public: + + /*! + * Constructor + * \param schemaPaths Vector of both paths and singular schemas + * Note: All schemas must end in *.xsd + * \param log Logger for reporting errors + * \param recursive Do a recursive search for schemas on directory + * input + */ + ValidatorLibXML(const std::vector& schemaPaths, + logging::Logger* log, + bool recursive = true) : + ValidatorInterface(schemaPaths, log, recursive) + { + throw except::Exception(Ctxt("LibXML Validation Unimplemented")); + } + + using ValidatorInterface::validate; + + /*! + * Validation against the internal schema pool + * \param xml The xml document string to validate + * \param xmlID Identifier for this input xml within the error log + * \param errors Object for returning errors found (errors are appended) + */ + virtual bool validate(const std::string& xml, + const std::string& xmlID, + std::vector& errors) const + { + throw except::Exception(Ctxt("LibXML Validation Unimplemented")); + } + +}; +} +} + +#endif + +#endif diff --git a/modules/c++/xml.lite/include/xml/lite/ValidatorXerces.h b/modules/c++/xml.lite/include/xml/lite/ValidatorXerces.h new file mode 100644 index 000000000..5c55e3ba4 --- /dev/null +++ b/modules/c++/xml.lite/include/xml/lite/ValidatorXerces.h @@ -0,0 +1,141 @@ +/* ========================================================================= + * This file is part of xml.lite-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2011, General Dynamics - Advanced Information Systems + * + * xml.lite-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __XML_LITE_VALIDATOR_XERCES_H__ +#define __XML_LITE_VALIDATOR_XERCES_H__ + +#ifdef USE_XERCES + +#include +#include + +#include "xml/lite/UtilitiesXerces.h" +#include "xml/lite/ValidatorInterface.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace xml +{ +namespace lite +{ + +typedef xercesc::DOMError ValidationError; + +class ValidationErrorHandler : public xercesc::DOMErrorHandler +{ +public: + ValidationErrorHandler() {} + + //! handle the errors during validation + virtual bool handleError (const ValidationError& err); + + //! get the raw information + const std::vector& getErrorLog() const + { + return mErrorLog; + } + + void clearErrorLog() { mErrorLog.clear(); } + + //! set the id to differentiate between errors + void setID(const std::string& id) { mID = id; } + + //! stream to a string + std::string toString() const + { + std::ostringstream oss; + for (size_t i = 0; i < mErrorLog.size(); ++i) + { + oss << mErrorLog[i] << std::endl; + } + return oss.str(); + } + +private: + std::vector mErrorLog; + std::string mID; +}; + +/*! + * \class ValidatorXerces + * \brief Schema validation is done here. + * + * This class is the Xercesc schema validator + */ +class ValidatorXerces : public ValidatorInterface +{ +private: + XercesContext mCtxt; //! this must be the first member listed + +public: + + /*! + * Constructor + * \param schemaPaths Vector of both paths and singular schemas + * Note: All schemas must end in *.xsd + * \param log Logger for reporting errors + * \param recursive Do a recursive search for schemas on directory + * input + */ + ValidatorXerces(const std::vector& schemaPaths, + logging::Logger* log, + bool recursive = true); + + using ValidatorInterface::validate; + + /*! + * Validation against the internal schema pool + * \param xml The xml document string to validate + * \param xmlID Identifier for this input xml within the error log + * \param errors Object for returning errors found (errors are appended) + */ + virtual bool validate(const std::string& xml, + const std::string& xmlID, + std::vector& errors) const; + +private: + + std::auto_ptr mSchemaPool; + std::auto_ptr mErrorHandler; + std::auto_ptr mValidator; + +}; +} +} + +//! stream the entire log -- newline separated +std::ostream& operator<< ( + std::ostream& out, + const xml::lite::ValidationErrorHandler& errorHandler); + +#endif + +#endif diff --git a/modules/c++/xml.lite/include/xml/lite/XMLException.h b/modules/c++/xml.lite/include/xml/lite/XMLException.h new file mode 100644 index 000000000..d391b2e65 --- /dev/null +++ b/modules/c++/xml.lite/include/xml/lite/XMLException.h @@ -0,0 +1,157 @@ +/* ========================================================================= + * This file is part of xml.lite-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * xml.lite-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __XML_LITE_XML_EXCEPTION_H__ +#define __XML_LITE_XML_EXCEPTION_H__ + +#include "except/Exception.h" + +/*! + * \file XMLException.h + * \brief Contains the exceptions specific to XML + * + * This file contains all of the specialized XML exceptions used by + * the xml::lite package + */ +namespace xml +{ +namespace lite +{ + +/*! + * \class XMLException + * \brief The base XML exception class + * + * This is the default XML exception, for when + * other, more specialized exception make no sense + */ +DECLARE_EXCEPTION(XML) + +/*! + * \class XMLNotRecognizedException + * \brief Specialized for badly formatted/incorrectly processed data + * + * Provides the derived implementation for bad formatting or + * for incorrect processing + */ +DECLARE_EXTENDED_EXCEPTION(XMLNotRecognized, xml::lite::XMLException) + +/*! + * \class XMLNotSupportedException + * \brief You might get this if we dont support some XML feature + * + * This is specifically for problems that occur with incompleteness + * of implementation, or with custom implementations on other + * systems that are not supported by the SAX/DOM standard + * + */ +DECLARE_EXTENDED_EXCEPTION(XMLNotSupported, xml::lite::XMLException) + +/*! + * \class XMLParseException + * \brief The interface for parsing exception + * + * This class provides the exception interface for handling + * XML exception while processing documents + * + */ +class XMLParseException : public XMLException +{ +public: + /*! + * Construct a parse exception + * \param message A message as presented by the parser + * \param row As reported by the parser + * \param column As reported by the parser + */ + XMLParseException(const char *message, int row = 0, int column = 0) : + XMLException(message) + { + form(row, column); + } + + /*! + * Construct a parse exception + * \param message A message as presented by the parser + * \param row As reported by the parser + * \param column As reported by the parser + * \param errNum An error number given by the parser + */ + XMLParseException(const std::string & message, int row = 0, int column = 0, + int errNum = 0) : + XMLException(message) + { + form(row, column); + } + + /*! + * Construct a parse exception + * \param c A context with a message as presented by the parser + * \param row As reported by the parser + * \param column As reported by the parser + * \param errNum An error number given by the parser + */ + XMLParseException(const except::Context& c, int row = 0, int column = 0, + int errNum = 0) : + XMLException(c) + { + form(row, column); + } + + /*! + * Constructor taking a Throwable and a Context + * \param t The Throwable + * \param c The exception Context + * \param row As reported by the parser + * \param column As reported by the parser + * \param errNum An error number given by the parser + */ + XMLParseException(const except::Throwable& t, const except::Context& c, + int row = 0, int column = 0, int errNum = 0) : + XMLException(t, c) + { + form(row, column); + } + + //! Destructor + virtual ~ XMLParseException() + { + } + +private: + + /*! + * Creates the actual message + * \param row As reported by the constructor + * \param col As reported by the constructor + * + */ + void form(int row, int column) + { + std::ostringstream oss; + oss << " (" << row << ',' << column << "): " << mMessage; + mMessage = oss.str(); + } +}; +} +} +#endif diff --git a/modules/c++/xml.lite/include/xml/lite/XMLReader.h b/modules/c++/xml.lite/include/xml/lite/XMLReader.h new file mode 100644 index 000000000..3e4f85d61 --- /dev/null +++ b/modules/c++/xml.lite/include/xml/lite/XMLReader.h @@ -0,0 +1,61 @@ +/* ========================================================================= + * This file is part of xml.lite-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * xml.lite-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __XML_LITE_XML_READER_H__ +#define __XML_LITE_XML_READER_H__ + + +#if defined(USE_XERCES) +# include "xml/lite/XMLReaderXerces.h" +namespace xml +{ +namespace lite +{ + +typedef XMLReaderXerces XMLReader; +} + +} +#elif defined(USE_LIBXML) +# include "xml/lite/XMLReaderLibXML.h" +namespace xml +{ +namespace lite +{ +typedef XMLReaderLibXML XMLReader; +} +} +#else +# if !defined(USE_EXPAT) +# define USE_EXPAT 1 +# endif +# include "xml/lite/XMLReaderExpat.h" +namespace xml +{ +namespace lite +{ +typedef XMLReaderExpat XMLReader; +} +} +#endif + +#endif diff --git a/modules/c++/xml.lite/include/xml/lite/XMLReaderExpat.h b/modules/c++/xml.lite/include/xml/lite/XMLReaderExpat.h new file mode 100644 index 000000000..10f59e7d6 --- /dev/null +++ b/modules/c++/xml.lite/include/xml/lite/XMLReaderExpat.h @@ -0,0 +1,248 @@ +/* ========================================================================= + * This file is part of xml.lite-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * xml.lite-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __XML_LITE_EXPAT_XML_READER_H__ +#define __XML_LITE_EXPAT_XML_READER_H__ + +#if defined(USE_EXPAT) +#include +#include +#include +#include "xml/lite/XMLException.h" +#include "xml/lite/ContentHandler.h" +#include "xml/lite/Attributes.h" +#include "xml/lite/NamespaceStack.h" +#include "xml/lite/XMLReaderInterface.h" + + +/*! + * \file + * \brief This a barebones XML implementation, based on the SAX 2.0 + * Specification, though it differs in many ways, as well. + * Where the specification deals with a design that is implemented via class + * upon interface upon interface, we are concerned more with the performance/ + * simplicity aspect. Thus, underlying interfaces + * which could be overlooked are, and API classes that could be finalized + * are. The classes are also simplified under the following assumptions. + * + * 1) The charset will be english only, and we are not doing utf16 + * + * 2) The error handler has been provided so that we can use the raise + * macro instead + * + * 3) We are not supporting DTD handling right now, and right now, we + * are non-validating. It is our opinion that DTDs are obsolete anyway, + * and should be replaced by XML schema where validation is needed. + * + * 4) Empty default implementations replace pure virtual here. If you + * bind a standard content handler, you will get an empty implementation + * automatically. + * + * The assertion here is that the user is a programmer interested more + * in speed and simplicity than a meaty implementation. Look at Apache + * Xerces, MSXML or even Arabica if this is not the case. + */ + +namespace xml +{ +namespace lite +{ +/*! + * \class XMLReader + * \brief SAX 2.0 XML Parsing class, replaces 1.0 Parser class + * Provide the API for SAX-driven parsing. We are using + * the Expat C Parser underneath, and wiring it to + * generic event calls, via the content handler. + */ +class XMLReaderExpat : public XMLReaderInterface +{ + + XML_Parser mNative; +public: + + //! Constructor. Creates a new XML parser + XMLReaderExpat() + { + mNative = NULL; + create(); + } + + //! Destructor. + ~XMLReaderExpat() + { + destroy(); + } + + /*! + * This method returns a reference to the content handler. + * \return content handler + */ + xml::lite::ContentHandler *getContentHandler() + { + return mContentHandler; + } + + /*! + * This method should be handed a new-allocated ContentHandler. + * It will set this internally. + * \param handler The content handler to pass + */ + void setContentHandler(xml::lite::ContentHandler * handler) + { + mContentHandler = handler; + } + + //! Finish parsing + void finish() + { + parse(NULL, 0, true); + mContentHandler->endDocument(); + } + + void parse(io::InputStream & is, + int size = io::InputStream::IS_END); + + //! Method to create an xml reader + void create(); + + //! Method to destroy an xml reader + void destroy(); + + const char *getErrorString(enum XML_Error errorCode) + { +#if defined (XML_UNICODE_WCHAR_T) +# error "For some reason, we are using wide characters" +#else + return (char *) XML_ErrorString(errorCode); +#endif + } + + int getCurrentLineNumber() + { + return XML_GetCurrentLineNumber(mNative); + } + + int getLastError() + { + return XML_GetErrorCode(mNative); + } + + int getCurrentColumnNumber() + { + return XML_GetCurrentColumnNumber(mNative); + } + + int getCurrentByteOffset() + { + return XML_GetCurrentByteIndex(mNative); + } + + std::string getDriverName() const { return "expat"; } + +private: + //! This is how we maintain our content handler + xml::lite::ContentHandler * mContentHandler; + + /*! + * This is the driver parser method + */ + void parse(const sys::byte *data, + int size, + bool done); + + /*! + * This is the mandatory io::OutputStream. + * \param data The buffer + * \param size The buffer size + */ + void write(const sys::byte * data, + sys::Size_T size) + { + parse(data, (int)size, false); + } + + //! Namespace mapping + xml::lite::NamespaceStack mNamespaceStack; + + + /*! + * Iterate through the raw attribute list and look for + * xmlns:prefix="uri" type mappings, and insert them + * on the namespace stack + */ + void pushNamespaceContext(const char **); + + //! Remove the context + void popNamespaceContext(); + + /*! + * Take the raw input, and resolve it to something our + * SAX 2.0 content handler knows about, and fire it + */ + static void commentCallback(void *, + const char *); + + /*! + * Take the raw input, and resolve it to something our + * SAX 2.0 content handler knows about, and fire it + */ + static void startElementCallback(void *, + const char *, + const char **); + + /*! + * Take the raw input, and resolve it to something our + * SAX 2.0 content handler knows about, and fire it + */ + static void endElementCallback(void *, + const char *); + + /*! + * Take the raw input, and resolve it to something our + * SAX 2.0 content handler knows about, and fire it + */ + static void charactersCallback(void *, + const char *, + int); + + /*! + * Resolve the name to all of the things the content handler + * wants + * \param name The input + * \param uri The uri + * \param localName The local name + * \param qname The QName + */ + void resolve(const char *name, + std::string& uri, + std::string& localName, + std::string& qname); + + +}; +} +} + +#endif + +#endif + diff --git a/modules/c++/xml.lite/include/xml/lite/XMLReaderInterface.h b/modules/c++/xml.lite/include/xml/lite/XMLReaderInterface.h new file mode 100644 index 000000000..8027392fb --- /dev/null +++ b/modules/c++/xml.lite/include/xml/lite/XMLReaderInterface.h @@ -0,0 +1,85 @@ +/* ========================================================================= + * This file is part of xml.lite-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * xml.lite-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __XML_LITE_ABSTRACT_XML_READER_H__ +#define __XML_LITE_ABSTRACT_XML_READER_H__ + +#include +#include "XMLException.h" + +namespace xml +{ +namespace lite +{ +class XMLReaderInterface : public io::OutputStream +{ +public: + + //! Constructor + XMLReaderInterface() + { + } + + //! Destructor + virtual ~XMLReaderInterface() + { + } + + /*! + * Returns the xml::lite::ContentHandler + * \return The ContentHandler + */ + virtual xml::lite::ContentHandler* getContentHandler() = 0; + + /*! + * Set the internal xml::lite::ContentHandler + * \param newHandler The ContentHandler to set + */ + virtual void setContentHandler(xml::lite::ContentHandler* newHandler) = 0; + + /*! + * Parse the input stream + * \param is The input stream to read from + * \param size The number of bytes to read + */ + void parse(io::InputStream & is, int size = io::InputStream::IS_END); + + //! Method to create an xml reader + virtual void create() = 0; + + //! Method to destroy an xml reader + virtual void destroy() = 0; + + virtual std::string getDriverName() const = 0; + +private: + //! Private copy constructor + XMLReaderInterface(const XMLReaderInterface &); + + //! Private overloaded assignment operator + XMLReaderInterface & operator=(const XMLReaderInterface &); + +}; +} +} + +#endif diff --git a/modules/c++/xml.lite/include/xml/lite/XMLReaderLibXML.h b/modules/c++/xml.lite/include/xml/lite/XMLReaderLibXML.h new file mode 100644 index 000000000..955342470 --- /dev/null +++ b/modules/c++/xml.lite/include/xml/lite/XMLReaderLibXML.h @@ -0,0 +1,206 @@ +/* ========================================================================= + * This file is part of xml.lite-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2011, General Dynamics - Advanced Information Systems + * + * xml.lite-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __XML_LITE_LIB_XML_READER_H__ +#define __XML_LITE_LIB_XML_READER_H__ + +#if defined(USE_LIBXML) + +#include +#include +#include +#include "xml/lite/XMLException.h" +#include "xml/lite/ContentHandler.h" +#include "xml/lite/Attributes.h" +#include "xml/lite/NamespaceStack.h" +#include "xml/lite/XMLReaderInterface.h" + +namespace xml +{ +namespace lite +{ + +class XMLReaderLibXML : public XMLReaderInterface +{ + + xmlSAXHandler mSAXLibXML; + xmlParserCtxt* mContextLibXML; + +public: + + //! Constructor. Creates a new XML parser + XMLReaderLibXML() + { + create(); + } + + //! Destructor. + ~XMLReaderLibXML() + { + destroy(); + } + + /*! + * This method returns a reference to the content handler. + * \return content handler + */ + xml::lite::ContentHandler *getContentHandler() + { + return mContentHandler; + } + + /*! + * This method should be handed a new-allocated ContentHandler. + * It will set this internally. + * \param handler The content handler to pass + */ + void setContentHandler(xml::lite::ContentHandler * handler) + { + mContentHandler = handler; + } + + //! Finish parsing + void finish() + { + parse(NULL, 0, true); + mContentHandler->endDocument(); + } + + void parse(io::InputStream & is, + int size = io::InputStream::IS_END); + + //! Method to create an xml reader + void create(); + + //! Method to destroy an xml reader + void destroy(); + + int getCurrentLineNumber() + { + + return xmlSAX2GetLineNumber(mContextLibXML); + } + + int getCurrentColumnNumber() + { + return xmlSAX2GetColumnNumber(mContextLibXML); + } + + std::string getDriverName() const { return "libxml"; } + +private: + //! This is how we maintain our content handler + xml::lite::ContentHandler* mContentHandler; + + /*! + * This is the driver parser method + */ + void parse(const sys::byte *data, + int size, + bool done); + + /*! + * This is the mandatory io::OutputStream. + * \param data The buffer + * \param size The buffer size + */ + void write(const sys::byte * data, + sys::Size_T size) + { + parse(data, (int)size, false); + } + + //! Namespace mapping + xml::lite::NamespaceStack mNamespaceStack; + + + /*! + * Iterate through the raw attribute list and look for + * xmlns:prefix="uri" type mappings, and insert them + * on the namespace stack + */ + void pushNamespaceContext(const xmlChar **); + + //! Remove the context + void popNamespaceContext(); + + + static void warningCallback(void *, + const char*, ...); + + static void errorCallback(void *, + const char*, ...); + + /*! + * Take the raw input, and resolve it to something our + * SAX 2.0 content handler knows about, and fire it + */ + static void commentCallback(void *, + const xmlChar *); + + /*! + * Take the raw input, and resolve it to something our + * SAX 2.0 content handler knows about, and fire it + */ + static void startElementCallback(void *, + const xmlChar *, + const xmlChar **); + + /*! + * Take the raw input, and resolve it to something our + * SAX 2.0 content handler knows about, and fire it + */ + static void endElementCallback(void *, + const xmlChar *); + + /*! + * Take the raw input, and resolve it to something our + * SAX 2.0 content handler knows about, and fire it + */ + static void charactersCallback(void *, + const xmlChar *, + int); + + + /*! + * Resolve the name to all of the things the content handler + * wants + * \param name The input + * \param uri The uri + * \param localName The local name + * \param qname The QName + */ + void resolve(const char *name, + std::string & uri, + std::string & localName, + std::string & qname); + + + +}; +} +} + +#endif + +#endif + diff --git a/modules/c++/xml.lite/include/xml/lite/XMLReaderXerces.h b/modules/c++/xml.lite/include/xml/lite/XMLReaderXerces.h new file mode 100644 index 000000000..3593a240d --- /dev/null +++ b/modules/c++/xml.lite/include/xml/lite/XMLReaderXerces.h @@ -0,0 +1,121 @@ +/* ========================================================================= + * This file is part of xml.lite-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * xml.lite-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#ifndef __XML_LITE_XERCES_XML_READER_H__ +#define __XML_LITE_XERCES_XML_READER_H__ + +#if defined(USE_XERCES) + +#include +#include +#include +#include +#include +#include +#include "xml/lite/XMLException.h" +#include "xml/lite/ContentHandler.h" +#include "xml/lite/Attributes.h" +#include "xml/lite/NamespaceStack.h" +#include "xml/lite/XMLReaderInterface.h" +#include "xml/lite/UtilitiesXerces.h" +#include + +namespace xml +{ +namespace lite +{ + +/*! + * \class XMLReaderXerces + * \brief SAX 2.0 XML Parsing class, replaces 1.0 Parser class + * + * Provide the API for SAX-driven parsing. We are using + * the Expat C Parser underneath, and wiring it to + * generic event calls, via the content handler. + */ +class XMLReaderXerces : public XMLReaderInterface +{ + +private: + + XercesContext mCtxt; //! this must be the first member listed + std::auto_ptr mNative; + std::auto_ptr mDriverContentHandler; + std::auto_ptr mErrorHandler; + +public: + + //! Constructor. Creates a new XML parser + XMLReaderXerces(); + + //! Destructor. + ~XMLReaderXerces() + { + } + + static const char* MEM_BUFFER_ID() + { + return "XMLReaderXerces"; + } + + /*! + * This method returns a reference to the content handler. + * \return content handler + */ + xml::lite::ContentHandler *getContentHandler() + { + return mDriverContentHandler->retrieveXMLLiteContentHandler(); + } + + /*! + * This method should be handed a new-allocated ContentHandler. + * It will set this internally. + * \param handler The content handler to pass + */ + void setContentHandler(xml::lite::ContentHandler* handler) + { + mDriverContentHandler->setXMLLiteContentHandler(handler); + } + + void parse(io::InputStream& is, int size = io::InputStream::IS_END); + + //! Method to create an xml reader + void create(); + + //! Method to destroy an xml reader + void destroy(); + + std::string getDriverName() const { return "xerces"; } + +private: + + void write(const sys::byte *b, sys::Size_T len) + { + throw xml::lite::XMLException(Ctxt("Im not sure how you got here!")); + } +}; + +} +} + +#endif +#endif diff --git a/modules/c++/xml.lite/source/Attributes.cpp b/modules/c++/xml.lite/source/Attributes.cpp new file mode 100644 index 000000000..11e232aed --- /dev/null +++ b/modules/c++/xml.lite/source/Attributes.cpp @@ -0,0 +1,194 @@ +/* ========================================================================= + * This file is part of xml.lite-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2011, General Dynamics - Advanced Information Systems + * + * xml.lite-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include "xml/lite/Attributes.h" + +xml::lite::AttributeNode::AttributeNode(const xml::lite::AttributeNode& node) +{ + mName = node.mName; + mValue = node.mValue; +} + +xml::lite::AttributeNode& +xml::lite::AttributeNode::operator=(const xml::lite::AttributeNode& node) +{ + if (&node != this) + { + mName = node.mName; + mValue = node.mValue; + } + return *this; +} + +int xml::lite::Attributes::getIndex(const std::string& qname) const +{ + + for (int i = 0; i < (int) mAttributes.size(); i++) + { + if (qname == mAttributes[i].getQName()) + return i; + } + return -1; +} + +int xml::lite::Attributes::getIndex(const std::string& uri, + const std::string& localName) const +{ + for (int i = 0; i < (int) mAttributes.size(); i++) + { + if ((uri == mAttributes[i].getUri()) && (localName + == mAttributes[i].getLocalName())) + return i; + } + return -1; + +} + +std::string xml::lite::Attributes::getValue(int i) const +{ + return mAttributes[i].getValue(); +} + +std::string xml::lite::Attributes::getUri(int i) const +{ + return mAttributes[i].getUri(); +} +std::string xml::lite::Attributes::getLocalName(int i) const +{ + return mAttributes[i].getLocalName(); +} + +std::string xml::lite::Attributes::getQName(int i) const +{ + return mAttributes[i].getQName(); +} + +std::string xml::lite::Attributes::getValue(const std::string& qname) const +{ + for (int i = 0; i < (int) mAttributes.size(); i++) + { + if (qname == mAttributes[i].getQName()) + return mAttributes[i].getValue(); + } + throw except::NoSuchKeyException(Ctxt(FmtX("QName '%s' could not be found", + qname.c_str()))); + + // We don't ever reach this but it keeps the compiler from complaining... + return mAttributes[(int) mAttributes.size() - 1].getValue(); +} + +std::string xml::lite::Attributes::getValue( + const std::string& uri, + const std::string& localName) const +{ + for (int i = 0; i < (int) mAttributes.size(); i++) + { + if ((uri == mAttributes[i].getUri()) && (localName + == mAttributes[i].getLocalName())) + return mAttributes[i].getValue(); + } + throw except::NoSuchKeyException(Ctxt(FmtX("(uri: %s, localName: %s", + uri.c_str(), localName.c_str()))); + + // We don't ever reach this but it keeps the compiler from complaining... + return mAttributes[(int) mAttributes.size() - 1].getValue(); +} + +void xml::lite::Attributes::add(const AttributeNode& attribute) +{ + mAttributes.push_back(attribute); +} + +void xml::lite::AttributeNode::setQName(const std::string& qname) +{ + mName.setQName(qname); +} + +void xml::lite::AttributeNode::setLocalName(const std::string& lname) +{ + mName.setName(lname); +} + +void xml::lite::AttributeNode::setPrefix(const std::string& prefix) +{ + mName.setPrefix(prefix); +} + +void xml::lite::AttributeNode::setUri(const std::string& uri) +{ + mName.setAssociatedUri(uri); +} + +void xml::lite::AttributeNode::setValue(const std::string& value) +{ + mValue = value; +} + +std::string xml::lite::AttributeNode::getUri() const +{ + return mName.getAssociatedUri(); +} + +std::string xml::lite::AttributeNode::getLocalName() const +{ + return mName.getName(); +} + +std::string xml::lite::AttributeNode::getPrefix() const +{ + return mName.getPrefix(); +} + +std::string xml::lite::AttributeNode::getValue() const +{ + return mValue; +} + +std::string xml::lite::AttributeNode::getQName() const +{ + return mName.toString(); +} + +xml::lite::Attributes::Attributes(const xml::lite::Attributes& attributes) +{ + mAttributes = attributes.mAttributes; +} + +xml::lite::Attributes& +xml::lite::Attributes::operator=(const xml::lite::Attributes& attributes) +{ + if (this != &attributes) + { + mAttributes = attributes.mAttributes; + } + return *this; +} + +const xml::lite::AttributeNode& xml::lite::Attributes::getNode(int i) const +{ + return mAttributes[i]; +} + +xml::lite::AttributeNode& xml::lite::Attributes::getNode(int i) +{ + return mAttributes[i]; +} diff --git a/modules/c++/xml.lite/source/Document.cpp b/modules/c++/xml.lite/source/Document.cpp new file mode 100644 index 000000000..95b3faacf --- /dev/null +++ b/modules/c++/xml.lite/source/Document.cpp @@ -0,0 +1,93 @@ +/* ========================================================================= + * This file is part of xml.lite-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2011, General Dynamics - Advanced Information Systems + * + * xml.lite-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include "xml/lite/Document.h" + +void xml::lite::Document::setRootElement(Element * element, bool own) +{ + destroy(); + mOwnRoot = own; + mRootNode = element; +} + +void xml::lite::Document::destroy() +{ + remove(mRootNode); +} + +void xml::lite::Document::remove(Element * toDelete) +{ + // Added code here to make sure we can remove from root + if (toDelete == mRootNode) + { + if (mRootNode && mOwnRoot) + delete mRootNode; + mRootNode = NULL; + } + else + remove(toDelete, mRootNode); +} + +xml::lite::Element * +xml::lite::Document::createElement(const std::string& qname, + const std::string& uri, + std::string characterData) +{ + Element *elem = new Element(); + elem->setQName(qname); + //std::cout << "qname: " << qname << std::endl; + + elem->setUri(uri); + elem->setCharacterData(characterData); + return elem; +} + +void xml::lite::Document::insert(xml::lite::Element * element, + xml::lite::Element * underThis) +{ + if (element != NULL && underThis != NULL) + underThis->addChild(element); +} + +void xml::lite::Document::remove(xml::lite::Element * toDelete, + xml::lite::Element * fromHere) +{ + if (fromHere != NULL && toDelete != NULL) + { + for (std::vector::iterator i = + fromHere->getChildren().begin(); i + != fromHere->getChildren().end(); ++i) + { + if (*i == toDelete) + { + fromHere->getChildren().erase(i); + delete toDelete; + toDelete = NULL; + return; + } + else + { + remove(toDelete, *i); + } + } + } +} diff --git a/modules/c++/xml.lite/source/Element.cpp b/modules/c++/xml.lite/source/Element.cpp new file mode 100644 index 000000000..376aa0119 --- /dev/null +++ b/modules/c++/xml.lite/source/Element.cpp @@ -0,0 +1,300 @@ +/* ========================================================================= + * This file is part of xml.lite-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2011, General Dynamics - Advanced Information Systems + * + * xml.lite-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include "xml/lite/Element.h" +#include + +xml::lite::Element::Element(const xml::lite::Element& node) +{ + // Assign each member + mName = node.mName; + mCharacterData = node.mCharacterData; + mAttributes = node.mAttributes; + mChildren = node.mChildren; + mParent = node.mParent; +} + +xml::lite::Element& xml::lite::Element::operator=(const xml::lite::Element& node) +{ + if (this !=&node) + { + mName = node.mName; + mCharacterData = node.mCharacterData; + mAttributes = node.mAttributes; + mChildren = node.mChildren; + mParent = node.mParent; + } + return *this; +} + +void xml::lite::Element::clone(const xml::lite::Element& node) +{ + mName = node.mName; + mCharacterData = node.mCharacterData; + mAttributes = node.mAttributes; + mParent = NULL; + + std::vector::const_iterator iter; + iter = node.getChildren().begin(); + for (; iter != node.getChildren().end(); ++iter) + { + xml::lite::Element *child = new xml::lite::Element(); + child->clone(**iter); + this->addChild(child); + } +} + +bool xml::lite::Element::hasElement(const std::string& uri, + const std::string& localName) const +{ + + for (unsigned int i = 0; i < mChildren.size(); i++) + { + if (mChildren[i]->getUri() == uri&& mChildren[i]->getLocalName() + == localName) + return true; + } + return false; +} + +bool xml::lite::Element::hasElement(const std::string& localName) const +{ + + for (unsigned int i = 0; i < mChildren.size(); i++) + { + if (mChildren[i]->getLocalName() == localName) + return true; + } + return false; +} + +void xml::lite::Element::getElementsByTagName(const std::string& uri, + const std::string& localName, + std::vector& elements, + bool recurse) const +{ + for (unsigned int i = 0; i < mChildren.size(); i++) + { + if (mChildren[i]->getUri() == uri && mChildren[i]->getLocalName() + == localName) + elements.push_back(mChildren[i]); + if (recurse) + mChildren[i]->getElementsByTagName(uri, localName, elements, recurse); + } +} + +void xml::lite::Element::getElementsByTagName(const std::string& localName, + std::vector& elements, + bool recurse) const +{ + for (unsigned int i = 0; i < mChildren.size(); i++) + { + if (mChildren[i]->getLocalName() == localName) + elements.push_back(mChildren[i]); + if (recurse) + mChildren[i]->getElementsByTagName(localName, elements, recurse); + } +} + +void xml::lite::Element::getElementsByTagNameNS(const std::string& qname, + std::vector& elements, + bool recurse) const +{ + for (unsigned int i = 0; i < mChildren.size(); i++) + { + if (mChildren[i]->mName.toString() == qname) + elements.push_back(mChildren[i]); + if (recurse) + mChildren[i]->getElementsByTagNameNS(qname, elements, recurse); + } +} + +void xml::lite::Element::destroyChildren() +{ + // While something is in vector + while (mChildren.size()) + { + // Get the last thing out + xml::lite::Element * childAtBack = mChildren.back(); + // Pop it off + mChildren.pop_back(); + // Delete it + delete childAtBack; + } +} + +void xml::lite::Element::print(io::OutputStream& stream) const +{ + depthPrint(stream, 0, ""); +} + +void xml::lite::Element::prettyPrint(io::OutputStream& stream, + std::string formatter) const +{ + depthPrint(stream, 0, formatter); + stream.writeln(""); +} + +void xml::lite::Element::depthPrint(io::OutputStream& stream, + int depth, + std::string formatter) const +{ + std::string prefix = ""; + for (int i = 0; i < depth; ++i) + prefix += formatter; + + // Printing in XML form, recursively + std::string lBrack = "<"; + std::string rBrack = ">"; + + std::string acc = prefix + lBrack + mName.toString(); + + for (int i = 0; i < mAttributes.getLength(); i++) + { + acc += std::string(" "); + acc += mAttributes.getQName(i); + acc += std::string("=\""); + acc += mAttributes.getValue(i); + acc += std::string("\""); + } + + if (mCharacterData.empty()&& mChildren.empty()) + { + //simple type - just end it here + stream.write(acc + "/" + rBrack); + } + else + { + stream.write(acc + rBrack); + stream.write(mCharacterData); + + for (unsigned int i = 0; i < mChildren.size(); i++) + { + if (!formatter.empty()) + stream.write("\n"); + mChildren[i]->depthPrint(stream, depth + 1, formatter); + } + + if (!mChildren.empty() && !formatter.empty()) + { + stream.write("\n" + prefix); + } + + lBrack += "/"; + stream.write(lBrack + mName.toString() + rBrack); + } +} + +void xml::lite::Element::addChild(xml::lite::Element * node) +{ + mChildren.push_back(node); + node->setParent(this); +} + +void xml::lite::Element::changePrefix(Element* element, + std::string prefix, std::string uri) +{ + if (element->mName.getAssociatedUri() == uri) + { + element->mName.setPrefix(prefix); + } + + // Traverse backward to support removing nodes + for (int i = element->mAttributes.getLength() - 1; i >= 0; i--) + { + if (element->mAttributes[i].getPrefix() == "xmlns" && + element->mAttributes[i].getValue() == uri) + { + // Remove all definitions of namespace + element->mAttributes.remove(i); + } + else if (element->mAttributes[i].getUri() == uri) + { + element->mAttributes[i].setPrefix(prefix); + } + } + + for (int i = 0, s = element->mChildren.size(); i < s; i++) + { + changePrefix(element->mChildren[i], prefix, uri); + } +} + +void xml::lite::Element::changeURI(Element* element, + std::string prefix, std::string uri) +{ + if (element->mName.getPrefix() == prefix) + { + element->mName.setAssociatedUri(uri); + } + + // Traverse backward to support removing nodes + for (int i = element->mAttributes.getLength() - 1; i >= 0; i--) + { + if (element->mAttributes[i].getPrefix() == "xmlns" && + element->mAttributes[i].getLocalName() == prefix) + { + // Remove all definitions of namespace + element->mAttributes.remove(i); + } + else if (element->mAttributes[i].getPrefix() == prefix) + { + element->mAttributes[i].setUri(uri); + } + } + + for (int i = 0, s = element->mChildren.size(); i < s; i++) + { + changeURI(element->mChildren[i], prefix, uri); + break; + } +} + +void xml::lite::Element::setNamespacePrefix(std::string prefix, std::string uri) +{ + str::trim(prefix); + changePrefix(this, prefix, uri); + + // Add namespace definition + ::xml::lite::Attributes& attr = getAttributes(); + + std::string p("xmlns"); + if (!prefix.empty()) + p += std::string(":") + prefix; + attr[p] = uri; +} + +void xml::lite::Element::setNamespaceURI(std::string prefix, std::string uri) +{ + str::trim(prefix); + changeURI(this, prefix, uri); + + // Add namespace definition + ::xml::lite::Attributes& attr = getAttributes(); + + std::string p("xmlns"); + if (!prefix.empty()) + p += std::string(":") + prefix; + attr[p] = uri; + + attr[std::string("xmlns:") + prefix] = uri; +} diff --git a/modules/c++/xml.lite/source/MinidomHandler.cpp b/modules/c++/xml.lite/source/MinidomHandler.cpp new file mode 100644 index 000000000..3aa4eeed8 --- /dev/null +++ b/modules/c++/xml.lite/source/MinidomHandler.cpp @@ -0,0 +1,145 @@ +/* ========================================================================= + * This file is part of xml.lite-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2011, General Dynamics - Advanced Information Systems + * + * xml.lite-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include "xml/lite/MinidomHandler.h" + +void xml::lite::MinidomHandler::setDocument(Document *newDocument, bool own) +{ + if (mDocument != NULL && mOwnDocument) + { + if (newDocument != mDocument) + delete mDocument; + } + mDocument = newDocument; + mOwnDocument = own; +} + +void xml::lite::MinidomHandler::clear() +{ + mDocument->destroy(); + currentCharacterData = ""; + assert(bytesForElement.empty()); + assert(nodeStack.empty()); +} + +void xml::lite::MinidomHandler::characters(const char *value, int length) +{ + // Append new data + if (length) + currentCharacterData += std::string(value, length); + + // Append number of bytes added to this node's stack value + assert(bytesForElement.size()); + bytesForElement.top() += length; +} + +void xml::lite::MinidomHandler::startElement(const std::string & uri, + const std::string & localName, + const std::string & qname, + const xml::lite::Attributes & atts) +{ + // Assign what we can now, and push rest on stack + // for later + + xml::lite::Element * current = mDocument->createElement(qname, uri); + + current->setAttributes(atts); + // Push this onto the node stack + nodeStack.push(current); + // Push a size of zero bytes on stack for this node's char data + bytesForElement.push(0); +} + +// This function subtracts off the char place from the push +std::string xml::lite::MinidomHandler::adjustCharacterData() +{ + // Edit the string with regard to this node's char data + // Get rid of what we take on char data accumulator + + int diff = (int) (currentCharacterData.length()) - bytesForElement.top(); + + std::string newCharacterData(currentCharacterData.substr( + diff, + currentCharacterData.length()) + ); + assert(diff >= 0); + currentCharacterData.erase(diff, currentCharacterData.length()); + if (!mPreserveCharData && !newCharacterData.empty()) + trim(newCharacterData); + + return newCharacterData; +} + +void xml::lite::MinidomHandler::trim(std::string & s) +{ + int i; + + for (i = 0; i < (int) s.length(); i++) + { + if (!isspace(s[i])) + break; + } + s.erase(0, i); + + for (i = (int) s.length() - 1; i >= 0; i--) + { + if (!isspace(s[i])) + break; + + } + if (i + 1 < (int) s.length()) + s.erase(i + 1); +} + +void xml::lite::MinidomHandler::endElement(const std::string & uri, + const std::string & localName, + const std::string & qname) +{ + // Pop current off top + xml::lite::Element * current = nodeStack.top(); + nodeStack.pop(); + + current->setCharacterData(adjustCharacterData()); + + // Remove corresponding int on bytes stack + bytesForElement.pop(); + // Something is left on the stack + // (We dont have not top-level node) + if (nodeStack.size()) + { + // Add current to child of parent + xml::lite::Element * parent = nodeStack.top(); + parent->addChild(current); + } + // This is the top-level node, and we are done + // Just Assign + else + { + mDocument->setRootElement(current); + } +} + +void xml::lite::MinidomHandler::preserveCharacterData(bool preserve) +{ + mPreserveCharData = preserve; +} + diff --git a/modules/c++/xml.lite/source/MinidomParser.cpp b/modules/c++/xml.lite/source/MinidomParser.cpp new file mode 100644 index 000000000..e69d73c9c --- /dev/null +++ b/modules/c++/xml.lite/source/MinidomParser.cpp @@ -0,0 +1,60 @@ +/* ========================================================================= + * This file is part of xml.lite-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2011, General Dynamics - Advanced Information Systems + * + * xml.lite-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include "xml/lite/MinidomParser.h" + +xml::lite::MinidomParser::MinidomParser() +{ + mReader.setContentHandler(&mHandler); +} + +void xml::lite::MinidomParser::parse(io::InputStream& is, + int size) +{ + mReader.parse(is, size); +} + +void xml::lite::MinidomParser::clear() +{ + mHandler.clear(); +} + +xml::lite::Document* xml::lite::MinidomParser::getDocument() const +{ + return mHandler.getDocument(); +} + +xml::lite::Document* xml::lite::MinidomParser::getDocument(bool steal) +{ + return mHandler.getDocument(steal); +} + +void xml::lite::MinidomParser::setDocument(xml::lite::Document* newDocument, + bool own) +{ + mHandler.setDocument(newDocument, own); +} + +void xml::lite::MinidomParser::preserveCharacterData(bool preserve) +{ + mHandler.preserveCharacterData(preserve); +} diff --git a/modules/c++/xml.lite/source/NamespaceStack.cpp b/modules/c++/xml.lite/source/NamespaceStack.cpp new file mode 100644 index 000000000..87bd43a78 --- /dev/null +++ b/modules/c++/xml.lite/source/NamespaceStack.cpp @@ -0,0 +1,71 @@ +/* ========================================================================= + * This file is part of xml.lite-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2011, General Dynamics - Advanced Information Systems + * + * xml.lite-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include "xml/lite/NamespaceStack.h" + +void xml::lite::NamespaceStack::push() +{ + mRefStack.push(0); +} + +void xml::lite::NamespaceStack::pop() +{ + int numToRemove = mRefStack.top(); + + for (int i = 0; i < numToRemove; i++) + { + // Remove this namespace mapping + mMappingStack.pop_back(); + } + + mRefStack.pop(); +} + + +void xml::lite::NamespaceStack::newMapping(const std::string& prefix, + const std::string& uri) +{ + ++mRefStack.top(); + mMappingStack.push_back(xml::lite::NamespaceEntity(prefix, uri)); +} + +std::string +xml::lite::NamespaceStack::getMapping(const std::string& prefix) const +{ + for (int i = (int)mMappingStack.size() - 1; i >= 0; --i) + { + if (mMappingStack[i].first == prefix) + { + return mMappingStack[i].second; + } + } + return std::string(""); +} + +void xml::lite::NamespaceStack:: +getAllPrefixes(std::vector& allPrefixes) const +{ + for (unsigned int i = 0; i < mMappingStack.size(); i++) + { + allPrefixes.push_back(mMappingStack[i].first); + } +} diff --git a/modules/c++/xml.lite/source/QName.cpp b/modules/c++/xml.lite/source/QName.cpp new file mode 100644 index 000000000..4d47c62e6 --- /dev/null +++ b/modules/c++/xml.lite/source/QName.cpp @@ -0,0 +1,81 @@ +/* ========================================================================= + * This file is part of xml.lite-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2011, General Dynamics - Advanced Information Systems + * + * xml.lite-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include "xml/lite/QName.h" + + + +std::string xml::lite::QName::getName() const +{ + return mLocalName; +} + +//! \return The fully qualifed qname (e.g., soap-env:SOAP-BODY) +std::string xml::lite::QName::toString() const +{ + std::string fullName; + if (mPrefix.length()) fullName = mPrefix + std::string(":"); + fullName += mLocalName; + return fullName; +} + +void xml::lite::QName::setName( const std::string& str) +{ + mLocalName = str; +} + +void xml::lite::QName::setPrefix( const std::string& prefix ) +{ + mPrefix = prefix; +} + +std::string xml::lite::QName::getPrefix() const +{ + return mPrefix; +} + + +void xml::lite::QName::setQName(const std::string& str) +{ + + size_t x = str.find_first_of(':'); + // Either we have a namespace prefix + if (x != std::string::npos) + { + setPrefix(str.substr(0, x)); + setName(str.substr(x + 1)); + } + else + { + setName(str); + } +} + +void xml::lite::QName::setAssociatedUri( const std::string& str ) +{ + mAssocUri = str; +} + +std::string xml::lite::QName::getAssociatedUri() const +{ + return mAssocUri; +} diff --git a/modules/c++/xml.lite/source/Serializable.cpp b/modules/c++/xml.lite/source/Serializable.cpp new file mode 100644 index 000000000..83598e721 --- /dev/null +++ b/modules/c++/xml.lite/source/Serializable.cpp @@ -0,0 +1,15 @@ +#include "xml/lite/Serializable.h" + +void xml::lite::Serializable::serialize(io::OutputStream& os) +{ + xml::lite::Element *root = getDocument()->getRootElement(); + if (root != NULL) + os.write("\n"); + root->print(os); +} + +void xml::lite::Serializable::deserialize(io::InputStream& is) +{ + //EVAL(is.available()); + mParser.parse(is); +} diff --git a/modules/c++/xml.lite/source/UtilitiesXerces.cpp b/modules/c++/xml.lite/source/UtilitiesXerces.cpp new file mode 100644 index 000000000..d30ee0ff9 --- /dev/null +++ b/modules/c++/xml.lite/source/UtilitiesXerces.cpp @@ -0,0 +1,232 @@ +/* ========================================================================= + * This file is part of xml.lite-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2011, General Dynamics - Advanced Information Systems + * + * xml.lite-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include "xml/lite/UtilitiesXerces.h" + +#if defined(USE_XERCES) + +sys::Mutex xml::lite::XercesContext::mMutex; + +xml::lite::XercesLocalString::XercesLocalString(XMLCh* xmlStr) : + mLocal(xmlStr) +{ +} + +xml::lite::XercesLocalString::XercesLocalString(const XMLCh* xmlStr) : + mLocal(XMLString::replicate(xmlStr)) +{ +} + +xml::lite::XercesLocalString::XercesLocalString(const char* str) : + mLocal(XMLString::transcode(str)) +{ +} + +xml::lite::XercesLocalString::XercesLocalString(const std::string& str) : + mLocal(XMLString::transcode(str.c_str())) +{ +} + +xml::lite::XercesLocalString:: +XercesLocalString(const XercesLocalString& rhs) +{ + mLocal = XMLString::replicate(rhs.toXMLCh()); +} + +xml::lite::XercesLocalString& xml::lite::XercesLocalString:: +operator=(XMLCh* xmlStr) +{ + // clean up old memory first + if (xmlStr != mLocal) + { + destroyXMLCh(&mLocal); + mLocal = xmlStr; + } + return *this; +} + +xml::lite::XercesLocalString& xml::lite::XercesLocalString:: +operator=(const XMLCh* xmlStr) +{ + // clean up old memory first + if (xmlStr != mLocal) + { + destroyXMLCh(&mLocal); + mLocal = XMLString::replicate(xmlStr); + } + return *this; +} + +xml::lite::XercesLocalString& xml::lite::XercesLocalString:: +operator=(const xml::lite::XercesLocalString& rhs) +{ + if (this != &rhs) + { + destroyXMLCh(&mLocal); + mLocal = XMLString::replicate(rhs.toXMLCh()); + } + return *this; +} + +void xml::lite::XercesContentHandler::characters(const XMLCh* const chars, + const XercesSize_T length) +{ + xml::lite::XercesLocalString xstr(chars); + mLiteHandler->characters(xstr.str().c_str(), (int)length); +} + +void xml::lite::XercesContentHandler::startDocument() +{ + mLiteHandler->startDocument(); +} + +void xml::lite::XercesContentHandler::endDocument() +{ + mLiteHandler->endDocument(); +} + +void xml::lite::XercesContentHandler::endElement(const XMLCh* const uri, + const XMLCh* const localName, + const XMLCh* const qname) +{ + xml::lite::XercesLocalString xuri(uri); + xml::lite::XercesLocalString xlocalName(localName); + xml::lite::XercesLocalString xqname(qname); + + mLiteHandler->endElement(xuri.str(), + xlocalName.str(), + xqname.str()); +} + +void xml::lite::XercesContentHandler::startElement( + const XMLCh* const uri, + const XMLCh* const localName, + const XMLCh* const qname, + const XercesAttributesInterface_T &attrs) +{ + // We have to copy the whole array + LiteAttributes_T attributes; + for (unsigned int i = 0; i < attrs.getLength(); i++) + { + LiteAttributesNode_T attributeNode; + attributeNode.setQName( + XercesLocalString(attrs.getQName(i)).str() + ); + + assert(attributeNode.getLocalName() == + XercesLocalString(attrs.getLocalName(i)).str()); + + attributeNode.setUri(XercesLocalString(attrs.getURI(i)).str()); + + attributeNode.setValue(XercesLocalString(attrs.getValue(i)).str()); + + //don't add duplicate attributes + if (attributes.getIndex(attributeNode.getUri(), + attributeNode.getLocalName()) == -1) + attributes.add(attributeNode); + } + + XercesLocalString xuri(uri); + XercesLocalString xlocalName(localName); + XercesLocalString xqname(qname); + mLiteHandler->startElement(xuri.str(), + xlocalName.str(), + xqname.str(), + attributes); +} + +void xml::lite::XercesErrorHandler:: +warning(const SAXParseException &exception) +{ +} + +void xml::lite::XercesErrorHandler:: +error(const SAXParseException &exception) +{ + XercesLocalString m(exception.getMessage()); + throw(xml::lite::XMLParseException(m.str(), + exception.getLineNumber(), + exception.getColumnNumber())); +} + +void xml::lite::XercesErrorHandler:: +fatalError(const SAXParseException &exception) +{ + XercesLocalString m(exception.getMessage()); + xml::lite::XMLParseException xex(m.str(), + exception.getLineNumber(), + exception.getColumnNumber()); + + throw except::Error(Ctxt(xex.getMessage())); +} + +xml::lite::XercesContext::XercesContext() : + mIsDestroyed(false) +{ + //! XMLPlatformUtils::Initialize is not thread safe! + try + { + mt::CriticalSection cs(&mMutex); + XMLPlatformUtils::Initialize(); + } + catch (const ::XMLException& toCatch) + { + xml::lite::XercesLocalString local(toCatch.getMessage()); + except::Error e(Ctxt(local.str() + " (Initialization error)")); + throw (e); + } +} + +xml::lite::XercesContext::~XercesContext() +{ + try + { + destroy(); + } + catch (...) + { + } +} + +void xml::lite::XercesContext::destroy() +{ + // wrapping it here saves the mutex lock + if (!mIsDestroyed) + { + //! XMLPlatformUtils::Terminate is not thread safe! + try + { + mt::CriticalSection cs(&mMutex); + XMLPlatformUtils::Terminate(); + mIsDestroyed = true; + } + catch (const ::XMLException& toCatch) + { + mIsDestroyed = false; + xml::lite::XercesLocalString local(toCatch.getMessage()); + except::Error e(Ctxt(local.str() + " (Termination error)")); + throw (e); + } + } +} + +#endif diff --git a/modules/c++/xml.lite/source/ValidatorXerces.cpp b/modules/c++/xml.lite/source/ValidatorXerces.cpp new file mode 100644 index 000000000..8a603439e --- /dev/null +++ b/modules/c++/xml.lite/source/ValidatorXerces.cpp @@ -0,0 +1,184 @@ +/* ========================================================================= + * This file is part of xml.lite-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2011, General Dynamics - Advanced Information Systems + * + * xml.lite-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ +#ifdef USE_XERCES + +#include "xml/lite/ValidatorXerces.h" +#include +#include +#include + +using namespace xml::lite; + +std::ostream& operator<< (std::ostream& out, + const ValidationErrorHandler& errorHandler) +{ + out << errorHandler.toString() << std::endl; + return out; +} + +bool xml::lite::ValidationErrorHandler::handleError( + const ValidationError& err) +{ + std::string level; + switch(err.getSeverity()) + { + case xercesc::DOMError::DOM_SEVERITY_WARNING : + level = "WARNING"; + break; + case xercesc::DOMError::DOM_SEVERITY_ERROR : + level = "ERROR"; + break; + case xercesc::DOMError::DOM_SEVERITY_FATAL_ERROR : + level = "FATAL"; + break; + default : + level = "WARNING"; + break; + } + + // transcode the file and message + xml::lite::XercesLocalString message(err.getMessage()); + + // create o + xml::lite::ValidationInfo info ( + message.str(), level, mID, + (size_t)err.getLocation()->getLineNumber()); + mErrorLog.push_back(info); + + return true; +} + + +ValidatorXerces::ValidatorXerces( + const std::vector& schemaPaths, + logging::Logger* log, + bool recursive) : + ValidatorInterface(schemaPaths, log, recursive) +{ + // add each schema into a grammar pool -- + // this allows reuse + mSchemaPool.reset( + new xercesc::XMLGrammarPoolImpl( + xercesc::XMLPlatformUtils::fgMemoryManager)); + + const XMLCh ls_id [] = {xercesc::chLatin_L, + xercesc::chLatin_S, + xercesc::chNull}; + + // create the validator + mValidator.reset( + xercesc::DOMImplementationRegistry:: + getDOMImplementation (ls_id)->createLSParser( + xercesc::DOMImplementationLS::MODE_SYNCHRONOUS, + 0, + xercesc::XMLPlatformUtils::fgMemoryManager, + mSchemaPool.get())); + + // set the configuration settings + xercesc::DOMConfiguration* config = mValidator->getDomConfig(); + config->setParameter(xercesc::XMLUni::fgDOMComments, false); + config->setParameter(xercesc::XMLUni::fgDOMDatatypeNormalization, true); + config->setParameter(xercesc::XMLUni::fgDOMEntities, false); + config->setParameter(xercesc::XMLUni::fgDOMNamespaces, true); + config->setParameter(xercesc::XMLUni::fgDOMElementContentWhitespace, false); + + // validation settings + config->setParameter(xercesc::XMLUni::fgDOMValidate, true); + config->setParameter(xercesc::XMLUni::fgXercesSchema, true); + config->setParameter(xercesc::XMLUni::fgXercesSchemaFullChecking, false); // this affects performance + + // definitely use cache grammer -- this is the cached schema + config->setParameter(xercesc::XMLUni::fgXercesUseCachedGrammarInParse, true); + + // explicitly skip loading schema referenced in the xml docs + config->setParameter(xercesc::XMLUni::fgXercesLoadSchema, false); + + // load additional schema referenced within schemas + config->setParameter(xercesc::XMLUni::fgXercesHandleMultipleImports, true); + + // it's up to the user to clear the cached schemas + config->setParameter(xercesc::XMLUni::fgXercesUserAdoptsDOMDocument, true); + + // add a error handler we still have control over + mErrorHandler.reset( + new xml::lite::ValidationErrorHandler()); + config->setParameter(xercesc::XMLUni::fgDOMErrorHandler, + mErrorHandler.get()); + + // load our schemas -- + // search each directory for schemas + sys::OS os; + std::vector schemas = + os.search(schemaPaths, "", ".xsd", recursive); + + // add the schema to the validator + for (size_t i = 0; i < schemas.size(); ++i) + { + if (!mValidator->loadGrammar(schemas[i].c_str(), + xercesc::Grammar::SchemaGrammarType, + true)) + { + std::ostringstream oss; + oss << "Error: Failure to load schema " << schemas[i]; + log->warn(Ctxt(oss.str())); + } + } + + //! no additional schemas will be loaded after this point! + mSchemaPool->lockPool(); +} + +bool ValidatorXerces::validate(const std::string& xml, + const std::string& xmlID, + std::vector& errors) const +{ + // clear the log before its use -- + // however we do not clear the users 'errors' because + // they might want an accumulation of errors + mErrorHandler->clearErrorLog(); + + // set the id so all errors coming from this session + // get a matching id + mErrorHandler->setID(xmlID); + + // get a vehicle to validate data + xercesc::DOMLSInputImpl input( + xercesc::XMLPlatformUtils::fgMemoryManager); + + // expand to the wide character data for use with xerces + xml::lite::XercesLocalString xmlWide(xml); + input.setStringData(xmlWide.toXMLCh()); + + // validate the document + mValidator->parse(&input)->release(); + + // add the new errors to the vector + errors.insert(errors.end(), + mErrorHandler->getErrorLog().begin(), + mErrorHandler->getErrorLog().end()); + + // reset the id + mErrorHandler->setID(""); + + return (!mErrorHandler->getErrorLog().empty()); +} +#endif diff --git a/modules/c++/xml.lite/source/XMLReaderExpat.cpp b/modules/c++/xml.lite/source/XMLReaderExpat.cpp new file mode 100644 index 000000000..346826937 --- /dev/null +++ b/modules/c++/xml.lite/source/XMLReaderExpat.cpp @@ -0,0 +1,240 @@ +/* ========================================================================= + * This file is part of xml.lite-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2011, General Dynamics - Advanced Information Systems + * + * xml.lite-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include "xml/lite/XMLReader.h" + +#if defined (USE_EXPAT) + + +// This parse routine knows the start of a document by definition +// It does not know the end +void xml::lite::XMLReaderExpat::parse(io::InputStream& is, int size) +{ + mContentHandler->startDocument(); + is.streamTo(*this, size); + finish(); + +} + +// This parse routine knows the end of a document based on the boolean done +// Thus, if done's value is incorrect, endDocument() will be inaccurate +void xml::lite::XMLReaderExpat::parse(const sys::byte *data, + int size, + bool done) +{ + if (!XML_Parse(mNative, (const char *)data, size, (int) done)) + throw + xml::lite::XMLParseException( + getErrorString((XML_Error) getLastError()), + getCurrentLineNumber(), + getCurrentColumnNumber() + ); +} + + +// This function creates the parser +void xml::lite::XMLReaderExpat::create() +{ + // 1. Take the default character mapping + // 2. Note we are not using expat's NS expanding + if (mNative == NULL) + mNative = XML_ParserCreate(NULL); + else + dbg_printf("Tried to re-create an existing parser!\n"); + + XML_SetUserData(mNative, this); + XML_SetElementHandler(mNative, + (XML_StartElementHandler) xml::lite::XMLReaderExpat:: + startElementCallback, + (XML_EndElementHandler) xml::lite::XMLReaderExpat:: + endElementCallback); + XML_SetCharacterDataHandler(mNative, + (XML_CharacterDataHandler) xml::lite:: + XMLReaderExpat::charactersCallback); + XML_SetCommentHandler(mNative, + (XML_CommentHandler) xml::lite::XMLReaderExpat:: + commentCallback); + +} + +// This function destroys the parser +void xml::lite::XMLReaderExpat::destroy() +{ + // 1. Delete the parser + // 2. Free the parser + XML_ParserFree(mNative); + mNative = NULL; +} + + +// This function puts the context on the stack +void xml::lite::XMLReaderExpat::pushNamespaceContext(const char **atts) +{ + mNamespaceStack.push(); + + // Iterate through and find the mappings + for (int i = 0; atts[i] != NULL; i += 2) + { + std::string attr(atts[i]); + std::string::size_type x = attr.find_first_of(':'); + + // Either we have a namespace prefix + if (x != std::string::npos) + { + // Either our namespace prefix is xmlns + if (attr.substr(0, x) == "xmlns") + { + // Get the value + std::string uri = atts[i + 1]; + mNamespaceStack.newMapping(attr.substr(x + 1), uri); + + } + // Or its not + } + else if (attr == "xmlns") + { + std::string u = atts[i + 1]; + mNamespaceStack.newMapping(attr, u); + } + } +} + +// This function removes the context from the stack +void xml::lite::XMLReaderExpat::popNamespaceContext() +{ + // All we have to do is pop the namespace stack context and we're done + mNamespaceStack.pop(); +} + + +// This method resolves a name to all of its SAX 2.0 parts +void xml::lite::XMLReaderExpat::resolve(const char *name, + std::string& uri, + std::string& lname, + std::string& qname) +{ + // The QName is the input + qname = name; + + // Find the delimiter if any + std::string::size_type x = qname.find_first_of(':'); + + // If it exists, set the associated uri and localName + if (x != std::string::npos) + { + uri = mNamespaceStack.getMapping(qname.substr(0, x)); + lname = qname.substr(x + 1); + } + // Check for xmlns then set the uri and local name to nothing + else + { + uri = mNamespaceStack.getMapping("xmlns"); + lname = qname; + } +} + +// This function fires off the content handler's startElement() function +void xml::lite::XMLReaderExpat::startElementCallback(void *p, + const char *tag, + const char **atts) +{ + // Pull out our parser + xml::lite::XMLReaderExpat * xmlReader = (xml::lite::XMLReaderExpat *) p; + + // Push the namespace context on for this element's attributes + xmlReader->pushNamespaceContext(atts); + + std::string uri; + std::string lname; + std::string qname; + + // Resolve the tag into what we really want + xmlReader->resolve(tag, uri, lname, qname); + + xml::lite::Attributes attrs; + // Resolve the attributes to what we really want + for (int i = 0; atts[i] != NULL; i += 2) + { + xml::lite::AttributeNode attr; + std::string attrQName; + std::string attrLName; + std::string attrUri; + + xmlReader->resolve(atts[i], + attrUri, + attrLName, + attrQName); + attr.setValue(atts[i + 1]); + + attr.setQName(attrQName); + attr.setUri(attrUri); + assert(attrLName == attr.getLocalName()); + attrs.add(attr); + } + + // Fire an event + xmlReader->getContentHandler()->startElement(uri, + lname, + qname, + attrs); +} + +// This function fires off the content handler's endElement() function +void xml::lite::XMLReaderExpat::endElementCallback(void *p, const char *tag) +{ + // Pull out our parser + xml::lite::XMLReaderExpat * xmlReader = (xml::lite::XMLReaderExpat *) p; + + std::string uri; + std::string localName; + std::string qname; + + // Resolve the tag into what we really want + xmlReader->resolve(tag, uri, localName, qname); + + // Fire the event + xmlReader->getContentHandler()->endElement(uri, localName, qname); + + xmlReader->popNamespaceContext(); +} + + +// This function fires off the content handler's characters() function +void xml::lite::XMLReaderExpat::charactersCallback(void *p, + const char *data, + int size) +{ + + // Pull out our parser + xml::lite::XMLReaderExpat* xmlReader = (xml::lite::XMLReaderExpat *) p; + xmlReader->getContentHandler()->characters(data, size); +} + +void xml::lite::XMLReaderExpat::commentCallback(void *p, const char *c) +{ + // Pull out our parser + xml::lite::XMLReaderExpat* xmlReader = (xml::lite::XMLReaderExpat *) p; + std::string cmt(c); + xmlReader->getContentHandler()->comment(cmt); +} + +#endif diff --git a/modules/c++/xml.lite/source/XMLReaderLibXML.cpp b/modules/c++/xml.lite/source/XMLReaderLibXML.cpp new file mode 100644 index 000000000..cd7650915 --- /dev/null +++ b/modules/c++/xml.lite/source/XMLReaderLibXML.cpp @@ -0,0 +1,284 @@ +/* ========================================================================= + * This file is part of xml.lite-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2011, General Dynamics - Advanced Information Systems + * + * xml.lite-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include "xml/lite/XMLReader.h" + +#if defined(USE_LIBXML) + + +// This parse routine knows the start of a document by definition +// It does not know the end +void xml::lite::XMLReaderLibXML::parse(io::InputStream& is, int size) +{ + mContentHandler->startDocument(); + is.streamTo(*this, size); + finish(); + +} + +// This parse routine knows the end of a document based on the boolean done +// Thus, if done's value is incorrect, endDocument() will be inaccurate +void xml::lite::XMLReaderLibXML::parse(const sys::byte *data, + int size, + bool done) +{ + // Gotta love this... piece of cake :) + if (xmlParseChunk(mContextLibXML, data, size, done) != 0) + throw xml::lite::XMLException(Ctxt("LibXML xmlParseChunk error")); +} + + +// This function creates the parser +void xml::lite::XMLReaderLibXML::create() +{ + //xmlSAX2InitDefaultSAXHandler(&mSAXLibXML, 0); + + xmlSAXVersion(&mSAXLibXML, 1); +/* + mSAXLibXML.internalSubset = NULL; + mSAXLibXML.externalSubset = NULL; + mSAXLibXML.isStandalone = NULL; + mSAXLibXML.hasInternalSubset = NULL; + mSAXLibXML.hasExternalSubset = NULL; + mSAXLibXML.resolveEntity = NULL; + mSAXLibXML.getEntity = NULL; + mSAXLibXML.getParameterEntity = NULL; + mSAXLibXML.entityDecl = NULL; + mSAXLibXML.attributeDecl = NULL; + mSAXLibXML.elementDecl = NULL; + mSAXLibXML.notationDecl = NULL; + mSAXLibXML.unparsedEntityDecl = NULL; + mSAXLibXML.setDocumentLocator = NULL; + mSAXLibXML.startDocument = NULL; + mSAXLibXML.endDocument = NULL; + mSAXLibXML.reference = NULL; + mSAXLibXML.cdataBlock = NULL; + mSAXLibXML.processingInstruction = NULL; +*/ + + mSAXLibXML.startDocument = NULL; + mSAXLibXML.endDocument = NULL; + mSAXLibXML.startElement = startElementCallback; + mSAXLibXML.endElement = endElementCallback; + mSAXLibXML.characters = charactersCallback; + mSAXLibXML.ignorableWhitespace = charactersCallback; + mSAXLibXML.comment = commentCallback; + mSAXLibXML.warning = warningCallback; + mSAXLibXML.error = errorCallback; + mSAXLibXML.fatalError = errorCallback; + + // Arguments are, in order: + // 1) SAX parser + // 2) User data + // 3) Chunk of data (presumably to allow it to test decoding) + // 4) Size (of chunk) + // 5) Filename (probably for parse error info) + // Returns the new parser context or NULL + mContextLibXML = + xmlCreatePushParserCtxt(&mSAXLibXML, + this, + NULL, + 0, + NULL); + + if (mContextLibXML == NULL) + throw except::Exception(Ctxt("Failed to create parser context")); + +} +// This function destroys the parser +void xml::lite::XMLReaderLibXML::destroy() +{ + if (mContextLibXML) + xmlFreeParserCtxt(mContextLibXML); + +} + + +// This function puts the context on the stack +void xml::lite::XMLReaderLibXML::pushNamespaceContext(const xmlChar **atts) +{ + mNamespaceStack.push(); + + // Iterate through and find the mappings + for (int i = 0; atts && atts[i] != NULL; i += 2) + { + std::string attr((const char*)atts[i]); + std::string::size_type x = attr.find_first_of(':'); + + // Either we have a namespace prefix + if (x != std::string::npos) + { + // Either our namespace prefix is xmlns + if (attr.substr(0, x) == "xmlns") + { + // Get the value + std::string uri( (const char*)atts[i + 1] ); + mNamespaceStack.newMapping(attr.substr(x + 1), uri); + + } + // Or its not + } + else if (attr == "xmlns") + { + std::string u( (const char*)atts[i + 1] ); + mNamespaceStack.newMapping(attr, u); + } + } +} + +// This function removes the context from the stack +void xml::lite::XMLReaderLibXML::popNamespaceContext() +{ + // All we have to do is pop the namespace stack context and we're done + mNamespaceStack.pop(); +} + + +// This method resolves a name to all of its SAX 2.0 parts +void xml::lite::XMLReaderLibXML::resolve(const char *name, + std::string& uri, + std::string& lname, + std::string& qname) +{ + // The QName is the input + qname = name; + + // Find the delimiter if any + std::string::size_type x = qname.find_first_of(':'); + + // If it exists, set the associated uri and localName + if (x != std::string::npos) + { + uri = mNamespaceStack.getMapping(qname.substr(0, x)); + lname = qname.substr(x + 1); + } + // Check for xmlns then set the uri and local name to nothing + else + { + uri = mNamespaceStack.getMapping("xmlns"); + lname = qname; + } +} + +// This function fires off the content handler's startElement() function +void xml::lite::XMLReaderLibXML::startElementCallback(void *ctx, + const xmlChar *tag, + const xmlChar **atts) +{ + // Pull out our parser + xml::lite::XMLReaderLibXML * xmlReader = (xml::lite::XMLReaderLibXML *) ctx; + + // Push the namespace context on for this element's attributes + xmlReader->pushNamespaceContext(atts); + + std::string uri; + std::string lname; + std::string qname; + + // Resolve the tag into what we really want + xmlReader->resolve((const char*)tag, uri, lname, qname); + + xml::lite::Attributes attrs; + // Resolve the attributes to what we really want + for (int i = 0; atts && atts[i] != NULL; i += 2) + { + xml::lite::AttributeNode attr; + std::string attrQName; + std::string attrLName; + std::string attrUri; + + xmlReader->resolve((const char*)atts[i], + attrUri, + attrLName, + attrQName); + attr.setValue((const char*)atts[i + 1]); + + attr.setQName(attrQName); + attr.setUri(attrUri); + assert(attrLName == attr.getLocalName()); + attrs.add(attr); + } + + // Fire an event + xmlReader->getContentHandler()->startElement(uri, + lname, + qname, attrs); +} + +// This function fires off the content handler's endElement() function +void xml::lite::XMLReaderLibXML::endElementCallback(void *ctx, const xmlChar *tag) +{ + // Pull out our parser + xml::lite::XMLReaderLibXML * xmlReader = (xml::lite::XMLReaderLibXML *) ctx; + + std::string uri; + std::string localName; + std::string qname; + + // Resolve the tag into what we really want + xmlReader->resolve((const char*)tag, uri, localName, qname); + + // Fire the event + xmlReader->getContentHandler()->endElement(uri, localName, qname); + + xmlReader->popNamespaceContext(); +} + + +// This function fires off the content handler's characters() function +void xml::lite::XMLReaderLibXML::charactersCallback(void *ctx, + const xmlChar *data, + int size) +{ + + // Pull out our parser + xml::lite::XMLReaderLibXML * xmlReader = (xml::lite::XMLReaderLibXML *) ctx; + xmlReader->getContentHandler()->characters((const char*)data, size); +} + +void xml::lite::XMLReaderLibXML::commentCallback(void *ctx, const xmlChar *c) +{ + // Pull out our parser + xml::lite::XMLReaderLibXML * xmlReader = (xml::lite::XMLReaderLibXML *) ctx; + std::string cmt((const char*)c); + xmlReader->getContentHandler()->comment(cmt); +} + +void xml::lite::XMLReaderLibXML::warningCallback(void *ctx, + const char* msg, + ...) +{ + // Do nothing for now, these should become wired up to something later +} + +void xml::lite::XMLReaderLibXML::errorCallback(void *ctx, + const char* msg, + ...) +{ + throw new xml::lite::XMLException(Ctxt(FmtX("LibXML parse exception: %s", msg))); +} + + + + + +#endif diff --git a/modules/c++/xml.lite/source/XMLReaderXerces.cpp b/modules/c++/xml.lite/source/XMLReaderXerces.cpp new file mode 100644 index 000000000..4f929cd32 --- /dev/null +++ b/modules/c++/xml.lite/source/XMLReaderXerces.cpp @@ -0,0 +1,80 @@ +/* ========================================================================= + * This file is part of xml.lite-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2011, General Dynamics - Advanced Information Systems + * + * xml.lite-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include "xml/lite/XMLReader.h" + +#if defined(USE_XERCES) + +xml::lite::XMLReaderXerces::XMLReaderXerces() +{ + create(); +} + +void xml::lite::XMLReaderXerces::parse(io::InputStream & is, int size) +{ + io::ByteStream byteStream; + is.streamTo(byteStream, size); + + off_t available = byteStream.available(); + if ( available <= 0 ) + { + throw xml::lite::XMLParseException(Ctxt("No stream available")); + } + sys::byte* buffer = new sys::byte[available]; + byteStream.read(buffer, available); + + // Adopt my buffer, and delete it for me + MemBufInputSource memBuffer((const unsigned char *)buffer, + available, + XMLReaderXerces::MEM_BUFFER_ID(), + false); + + mNative->parse(memBuffer); + + delete [] buffer; +} + +// This function creates the parser +void xml::lite::XMLReaderXerces::create() +{ + mDriverContentHandler.reset(new XercesContentHandler()); + mErrorHandler.reset(new XercesErrorHandler()); + + mNative.reset(XMLReaderFactory::createXMLReader()); + mNative->setFeature(XMLUni::fgSAX2CoreNameSpacePrefixes, true); + mNative->setFeature(XMLUni::fgSAX2CoreValidation, false); // optional + mNative->setFeature(XMLUni::fgSAX2CoreNameSpaces, true); // optional + mNative->setFeature(XMLUni::fgXercesSchema, false); + mNative->setContentHandler(mDriverContentHandler.get()); + mNative->setErrorHandler(mErrorHandler.get()); +} +// This function destroys the parser +void xml::lite::XMLReaderXerces::destroy() +{ + mNative.reset(); + mDriverContentHandler.reset(); + mErrorHandler.reset(); + + mCtxt.destroy(); +} + +#endif diff --git a/modules/c++/xml.lite/tests/AttributeValueTest.cpp b/modules/c++/xml.lite/tests/AttributeValueTest.cpp new file mode 100644 index 000000000..115b4bfa9 --- /dev/null +++ b/modules/c++/xml.lite/tests/AttributeValueTest.cpp @@ -0,0 +1,80 @@ +/* ========================================================================= + * This file is part of xml.lite-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2011, General Dynamics - Advanced Information Systems + * + * xml.lite-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#if defined (USE_EXPAT) || defined(USE_XERCES) || defined(USE_LIBXML) + +#include +#include +#include +//#include +using namespace std; +using namespace io; +using namespace xml::lite; +using namespace except; + +int main(int argc, char **argv) +{ +// NotificationSingleton().changeHandler(new +// LogExHandler(new StandardErrStream)); + try + { + StandardOutStream out; + + // Check to make sure we have right length + if (argc != 2) + throw Exception(Ctxt(FmtX("Usage: %s \n", argv[0]))); + + // Create an input stream + FileInputStream xmlFile(argv[1]); + + // Create an XML parse tree + MinidomParser treeBuilder; + // Use the provided parse method to parse the input file + treeBuilder.parse(xmlFile); + + // Get the top level node so we can manipulate the tree + Element *rootNode = treeBuilder.getDocument()->getRootElement(); + + cout << "Getting value" << endl; + std::string v = rootNode->getAttributes().getValue("A"); + cout << v << endl; + int idx = rootNode->getAttributes().getIndex("A"); + cout << rootNode->getAttributes().getQName(idx) << endl; + + + rootNode->print(out); + } + // Catch all throwables and exit in a reasonable manner + catch (Throwable & t) + { + cout << "Caught Throwable: " << t.toString() << endl; + + // If we caught an exception, exit unfavorably. + exit(EXIT_FAILURE); + } + return 0; +} +#else +int main() +{} +#endif + diff --git a/modules/c++/xml.lite/tests/ClearTest.cpp b/modules/c++/xml.lite/tests/ClearTest.cpp new file mode 100644 index 000000000..3fb0f8afc --- /dev/null +++ b/modules/c++/xml.lite/tests/ClearTest.cpp @@ -0,0 +1,73 @@ +/* ========================================================================= + * This file is part of xml.lite-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2011, General Dynamics - Advanced Information Systems + * + * xml.lite-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include +#include +#include +#include +const char + * xmldata = + "Thisisanuglyotter"; +void printCD(std::string tag, std::vector& e) +{ + std::cout << tag << ": "; + for (size_t i = 0; i < e.size(); ++i) + { + std::cout << e[i]->getCharacterData(); + std::cout << " "; + } + std::cout << std::endl; +} + +int main() +{ + io::StringStream ss; + ss.write(xmldata, strlen(xmldata)); + xml::lite::MinidomParser p; + p.parse(ss); + xml::lite::Element* elem = p.getDocument()->getRootElement(); + + std::vector vec; + elem->getElementsByTagName("A", vec); + printCD("A", vec); + vec.clear(); + + elem->getElementsByTagName("B", vec); + printCD("B", vec); + vec.clear(); + + elem->getElementsByTagName("B", vec, true); + printCD("B", vec); + vec.clear(); + + xml::lite::AttributeNode attr; + attr.setQName("better"); + attr.setValue("1"); + xml::lite::Attributes atts; + atts.add(attr); + elem->setAttributes(atts); + + io::StandardOutStream sout; + elem->print(sout); + std::cout << std::endl; +} + diff --git a/modules/c++/xml.lite/tests/MMParserTest1.cpp b/modules/c++/xml.lite/tests/MMParserTest1.cpp new file mode 100644 index 000000000..6c7a8e5cf --- /dev/null +++ b/modules/c++/xml.lite/tests/MMParserTest1.cpp @@ -0,0 +1,95 @@ +/* ========================================================================= + * This file is part of xml.lite-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2009, General Dynamics - Advanced Information Systems + * + * xml.lite-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#if defined (USE_EXPAT) || defined(USE_XERCES) || defined(USE_LIBXML) + +#include +#include +#include +//#include +using namespace std; +using namespace io; +using namespace xml::lite; +using namespace except; + +int main(int argc, char **argv) +{ + try + { + + // Check to make sure we have right length + if (argc != 3) + die_printf("Usage: %s --map|--file \n", argv[0]); + + InputStream* xmlFile; + // Create an input stream + std::string flags = argv[1]; + if (flags == "--file") + xmlFile = new FileInputStream(argv[2]); + else if (flags == "--map") + xmlFile = new MMapInputStream(argv[2]); + else + die_printf("Invalid flag: [%s]\n", flags.c_str()); + + + + // Create an XML parse tree + MinidomParser treeBuilder; +//#if defined(USE_XERCES) +// treeBuilder.getReader().setValidation(true); +//#endif + // Use the provided parse method to parse the input file + treeBuilder.parse(*xmlFile); + + + std::cout << "Finished!" << std::endl; + /* + // Get the top level node so we can manipulate the tree + Element *rootNode = treeBuilder.getDocument()->getRootElement(); + + //assert(rootNode2 == rootNode); + // cout << "========== Begin XML Tree ==========" << endl; + StandardOutStream out; + + rootNode->print(out); + // cout << "========== End XML Tree ==========" << endl; + + */ + // The Tree should delete itself + delete xmlFile; + + } + // Catch all throwables and exit in a reasonable manner + catch (Throwable & t) + { + cout << "Caught Throwable: " << t.toString() << endl; + + // If we caught an exception, exit unfavorably. + exit(EXIT_FAILURE); + } + return 0; +} +#else +int main() +{} +#endif + diff --git a/modules/c++/xml.lite/tests/MinidomParserTest1.cpp b/modules/c++/xml.lite/tests/MinidomParserTest1.cpp new file mode 100644 index 000000000..1d947eb9b --- /dev/null +++ b/modules/c++/xml.lite/tests/MinidomParserTest1.cpp @@ -0,0 +1,73 @@ +/* ========================================================================= + * This file is part of xml.lite-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2011, General Dynamics - Advanced Information Systems + * + * xml.lite-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#if defined (USE_EXPAT) || defined(USE_XERCES) || defined(USE_LIBXML) + +#include +#include +#include +//#include +using namespace std; +using namespace io; +using namespace xml::lite; +using namespace except; + +int main(int argc, char **argv) +{ + try + { + StandardOutStream out; + + // Check to make sure we have right length + if (argc != 2) + throw Exception(Ctxt(FmtX("Usage: %s \n", argv[0]))); + + // Create an input stream + FileInputStream xmlFile(argv[1]); + + // Create an XML parse tree + MinidomParser treeBuilder; +//#if defined(USE_XERCES) +// treeBuilder.getReader().setValidation(true); +//#endif + // Use the provided parse method to parse the input file + treeBuilder.parse(xmlFile); + + Element *rootNode = treeBuilder.getDocument()->getRootElement(); + + rootNode->prettyPrint(out); + } + // Catch all throwables and exit in a reasonable manner + catch (Throwable & t) + { + cout << "Caught Throwable: " << t.toString() << endl; + + // If we caught an exception, exit unfavorably. + exit(EXIT_FAILURE); + } + return 0; +} +#else +int main() +{} +#endif + diff --git a/modules/c++/xml.lite/tests/MinidomParserTest2.cpp b/modules/c++/xml.lite/tests/MinidomParserTest2.cpp new file mode 100644 index 000000000..969b34d4f --- /dev/null +++ b/modules/c++/xml.lite/tests/MinidomParserTest2.cpp @@ -0,0 +1,207 @@ +/* ========================================================================= + * This file is part of xml.lite-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2011, General Dynamics - Advanced Information Systems + * + * xml.lite-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#if defined (USE_EXPAT) || defined(USE_XERCES) || defined(USE_LIBXML) +#include +#include +#include +#include +#include + +using namespace std; +using namespace sys; +using namespace io; +using namespace xml::lite; +using namespace except; + +const std::string ROOT_TAG = "deploy"; +const std::string ROOT_URI = ""; +const std::string SERVICE_TAG = "service"; +const std::string SERVICE_URI = ""; +const std::string LOCATION_TAG = "location"; +const std::string LOCATION_URI = ""; +const std::string NAME_TAG = "name"; +const std::string NAME_URI = ""; + +void addService(Document *doc, Element *rootElement, string name, string location); +bool removeService(Document *doc, Element *rootElement, string name); +bool findService(Document *doc, Element *rootElement, string name); + +int main(int argc, char **argv) +{ + try + { + if (argc != 5) + { + throw Exception(Ctxt(FmtX( + "Usage: %s [OPTION] \n\n\t-a\tadd service\n\t-s\tsubtract service\n\t-o\toutput file\n", + argv[0]))); + } + + StandardOutStream out; + + // Create an XML parse tree + MinidomParser treeBuilder; +#if defined(USE_XERCES) + treeBuilder.getReader().setValidation(true); +#endif + + sys::OS os; + + if (!os.exists(argv[4])) + { + FileOutputStream os(argv[4]); + os.write("\n"); + os.close(); + } + FileInputStream inXmlFile(argv[4]); + + // Use the provided parse method to parse the input file + treeBuilder.parse(inXmlFile); + + inXmlFile.close(); + + Document *doc = treeBuilder.getDocument(); + Element *rootElement = doc->getRootElement(); + + string name = argv[2]; + string location = argv[3]; + + FileOutputStream outXmlFile; + + if (!rootElement) + { + rootElement = doc->createElement(ROOT_TAG, ROOT_URI, ROOT_TAG); + doc->setRootElement(rootElement); + } + else if (rootElement->getLocalName() != ROOT_TAG) + { + throw Exception(Ctxt("Invalid deploy file")); + } + + switch (argv[1][1]) + { + case 'a': + addService(doc, rootElement, name, location); +#if defined(USE_IO_STREAMS) + outXmlFile.open(argv[4]); +#else + outXmlFile.create(argv[4]); +#endif + if (rootElement) rootElement->print(outXmlFile); + break; + case 's': + removeService(doc, rootElement, name); + rootElement = doc->getRootElement(); +#if defined(USE_IO_STREAMS) + outXmlFile.open(argv[4]); +#else + outXmlFile.create(argv[4]); +#endif + if (rootElement) rootElement->print(outXmlFile); + break; + case 'o': + if (rootElement) rootElement->print(out); + break; + default: + throw Exception(Ctxt(FmtX( + "Usage: %s [OPTION] \n\n\t-a\tadd service\n\t-s\tsubtract service\n\t-o\toutput file\n", + argv[0]))); + } + + outXmlFile.close(); + + } // Catch all throwables and exit in a reasonable manner + catch (Throwable & t) + { + cout << t.toString() << endl; + // If we caught an exception, exit unfavorably. + exit(EXIT_FAILURE); + } + return 0; +} + + +void addService(Document *doc, Element *rootElement, string name, string location) +{ + Element *toAdd, *child; + + if (findService(doc, rootElement, name)) return; + + toAdd = doc->createElement(SERVICE_TAG, SERVICE_URI, "" ); + child = doc->createElement(NAME_TAG, NAME_URI, NAME_TAG); + child->setCharacterData(name); + toAdd->addChild(child); + child = doc->createElement(LOCATION_TAG, LOCATION_URI, ""); + child->setCharacterData(location); + toAdd->addChild(child); + + doc->insert(toAdd, rootElement); +} + +bool removeService(Document *doc, Element *rootElement, string name) +{ + bool found(false); + vector< Element* >::iterator childIterator; + + childIterator = rootElement->getChildren().begin(); + for (; childIterator != rootElement->getChildren().end(); ++childIterator) + { + if ((*childIterator)->getCharacterData() == name) + { + doc->remove(rootElement); + return true; + } + else + { + found = removeService(doc, *childIterator, name); + if (found) return true; + } + } + return false; +} + +bool findService(Document *doc, Element *rootElement, string name) +{ + bool found(false); + vector< Element* >::iterator childIterator; + + childIterator = rootElement->getChildren().begin(); + for (; childIterator != rootElement->getChildren().end(); ++childIterator) + { + if ((*childIterator)->getCharacterData() == name) + { + return true; + } + else + { + found = findService(doc, *childIterator, name); + if (found) return true; + } + } + return false; +} +#else +int main() +{} +#endif + diff --git a/modules/c++/xml.lite/tests/NamespaceStackTest.cpp b/modules/c++/xml.lite/tests/NamespaceStackTest.cpp new file mode 100644 index 000000000..20c37fa32 --- /dev/null +++ b/modules/c++/xml.lite/tests/NamespaceStackTest.cpp @@ -0,0 +1,81 @@ +/* ========================================================================= + * This file is part of xml.lite-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2011, General Dynamics - Advanced Information Systems + * + * xml.lite-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include +#include +using namespace xml::lite; + +using namespace std; + +int main() +{ + NamespaceStack xmlNs; + + // Push new context + xmlNs.push(); + + xmlNs.newMapping("x", "some-uri"); + xmlNs.newMapping("y", "some-uri"); + + xmlNs.push(); + + xmlNs.newMapping("x", "new-uri"); + xmlNs.newMapping("z", "local"); + + // Level two ///////////////////////////////// + + + // This exists, but it has been mapped over + std::string uri_x2 = xmlNs.getMapping("x"); + cout << "In Level 2 (x): " << uri_x2 << endl; + + // This exists in global scope + std::string uri_y2 = xmlNs.getMapping("y"); + cout << "In Level 2 (y): " << uri_y2 << endl; + + // This exists only in local scope + std::string uri_z2 = xmlNs.getMapping("z"); + cout << "In Level 2 (z): " << uri_z2 << endl; + + // Level two ///////////////////////////////// + + xmlNs.pop(); + + // Level one ///////////////////////////////// + + // This should now be the old value + std::string uri_x1 = xmlNs.getMapping("x"); + cout << "In Level 1 (x): " << uri_x1 << endl; + + // This should not change + std::string uri_y1 = xmlNs.getMapping("y"); + cout << "In Level 1 (y): " << uri_y1 << endl; + + // This should no longer exist, and thus be blank + std::string uri_z1 = xmlNs.getMapping("z"); + cout << "In Level 1 (z): " << uri_z1 << endl; + + // Level one ///////////////////////////////// + + xmlNs.pop(); + return 0; +}; diff --git a/modules/c++/xml.lite/tests/RewritePrefix.cpp b/modules/c++/xml.lite/tests/RewritePrefix.cpp new file mode 100644 index 000000000..4045d76de --- /dev/null +++ b/modules/c++/xml.lite/tests/RewritePrefix.cpp @@ -0,0 +1,65 @@ +/* ========================================================================= + * This file is part of xml.lite-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2011, General Dynamics - Advanced Information Systems + * + * xml.lite-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#if defined(USE_EXPAT) || defined(USE_XERCES) || defined(USE_LIBXML) +#include +#include +#include + +int main(int argc, char **argv) +{ + if (argc != 5) + die_printf("Usage: %s \n", + argv[0]); + + try + { + + std::string file = argv[1]; + std::string prefix = argv[2]; + std::string uri = argv[3]; + std::string outfile = argv[4]; + + std::cout << "Replacing all prefixes for uri " << uri + << " with prefix " << prefix << std::endl; + io::FileInputStream fis( file ); + + xml::lite::MinidomParser parser; + parser.parse(fis); + xml::lite::Element* topLevel = parser.getDocument()->getRootElement(); + topLevel->setNamespacePrefix( prefix, uri ); + io::FileOutputStream fos( outfile ); + topLevel->prettyPrint( fos ); + } + catch (except::Throwable& anything) + { + std::cout << "Caught throwable: " << anything.getType() << " " + << anything.toString() << std::endl; + + } + +} +#else +int main() +{} +#endif + diff --git a/modules/c++/xml.lite/tests/RewriteUri.cpp b/modules/c++/xml.lite/tests/RewriteUri.cpp new file mode 100644 index 000000000..551c876c8 --- /dev/null +++ b/modules/c++/xml.lite/tests/RewriteUri.cpp @@ -0,0 +1,66 @@ +/* ========================================================================= + * This file is part of xml.lite-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2011, General Dynamics - Advanced Information Systems + * + * xml.lite-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#if defined(USE_EXPAT) || defined(USE_XERCES) || defined(USE_LIBXML) + +#include +#include +#include + +int main(int argc, char **argv) +{ + if (argc != 5) + die_printf("Usage: %s \n", + argv[0]); + + try + { + + std::string file = argv[1]; + std::string prefix = argv[2]; + std::string uri = argv[3]; + std::string outfile = argv[4]; + + std::cout << "Replacing all matching prefixes " << prefix + << " with uri " << uri << std::endl; + io::FileInputStream fis( file ); + + xml::lite::MinidomParser parser; + parser.parse(fis); + xml::lite::Element* topLevel = parser.getDocument()->getRootElement(); + topLevel->setNamespaceURI( prefix, uri ); + io::FileOutputStream fos( outfile ); + topLevel->prettyPrint( fos ); + } + catch (except::Throwable& anything) + { + std::cout << "Caught throwable: " << anything.getType() << " " + << anything.toString() << std::endl; + + } + +} +#else +int main() +{} +#endif + diff --git a/modules/c++/xml.lite/tests/ValidationTest.cpp b/modules/c++/xml.lite/tests/ValidationTest.cpp new file mode 100644 index 000000000..0544274fc --- /dev/null +++ b/modules/c++/xml.lite/tests/ValidationTest.cpp @@ -0,0 +1,60 @@ +#include +#include +#include +#include +#include +#include + +int main(int argc, char** argv) +{ + try + { + // create a parser and add our options to it + cli::ArgumentParser parser; + parser.setDescription("The detected image processor."); + parser.addArgument("-s --schema", "path to schema directory", + cli::STORE)->setDefault("."); + parser.addArgument("-r --recursive", "recursively search for schemas", + cli::STORE_TRUE)->setDefault(false); + parser.addArgument("-x --xml", "xml document to validate", + cli::STORE); + // parse! + const std::auto_ptr + options(parser.parse(argc, (const char**) argv)); + std::auto_ptr log( + logging::setupLogger("ValidationTest")); + + std::vector schemaPaths; + schemaPaths.push_back(options->get ("schema")); + xml::lite::Validator validator(schemaPaths, + log.get(), + options->get ("recursive")); + + std::vector errors; + sys::Path path(options->get ("xml")); + + io::FileInputStream fis(path.getPath()); + if (validator.validate(fis, path.getPath(), errors)) + { + for (size_t i = 0; i < errors.size(); ++i) + { + std::cout << errors[i] << std::endl; + } + } + fis.close(); + } + catch (const except::Exception& ex) + { + std::cout << "CODA Exception: " << ex.getMessage() << std::endl; + } + catch (const std::exception& ex) + { + std::cout << "STD Exception: " << ex.what() << std::endl; + } + catch (...) + { + std::cout << "Unknown Exception: " << "System Error!" << std::endl; + } + + return 0; +} diff --git a/modules/c++/xml.lite/tests/XMLReaderTest.cpp b/modules/c++/xml.lite/tests/XMLReaderTest.cpp new file mode 100644 index 000000000..3970baf8e --- /dev/null +++ b/modules/c++/xml.lite/tests/XMLReaderTest.cpp @@ -0,0 +1,168 @@ +/* ========================================================================= + * This file is part of xml.lite-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2011, General Dynamics - Advanced Information Systems + * + * xml.lite-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +/*! + * \file XMLEventReaderTest.cpp + * \brief Test to prove the XMLEventReader worth + * + * This will first stream the input file to a temp file. Then it will attempt + * to parse it with the Reporter class, a direct descendant of the + * XMLEventReader. For an interesting test, run it with the argument of + * make.xml (if it is in this folder). + * + */ +#if defined(USE_EXPAT) || defined(USE_XERCES) || defined(USE_LIBXML) + +#include +#include +#include +#include + +using namespace std; +using namespace io; +using namespace sys; +using namespace except; +using namespace xml::lite; + +class Reporter : public xml::lite::ContentHandler +{ +public: + Reporter() : mDepth(0) + {} + ~Reporter() + {} + + void printAttributes(const xml::lite::Attributes& attr) + { + for (int i = 0; i < attr.getLength(); i++) + { + cout << "Attribute " << i << ": " << endl; + cout << "Uri: " << attr.getUri(i) << endl; + cout << "Local: " << attr.getLocalName(i) << endl; + cout << "QName: " << attr.getUri(i) << endl; + cout << "Value: " << attr.getValue(i) << endl; + } + } + + /*! + * Define char data method. Fired when character data is found. + * \param data The data picked up by the handler + * \param length The length of the data picked up by the handler + */ + void characters(const char *data, int length) + { + // Do nothing: Im not interested in keeping track of this + } + + /*! + * Define start element method. Fired when a begin tag is found. + * \param name The name of the tag + * \param atts A list of attributes in the begin tag + */ + void startElement(const std::string & uri, + const std::string & localName, + const std::string & qname, + const xml::lite::Attributes & atts) + { + printDepth(); + cout << "START ELEMENT " + << "(uri=\"" << uri << "\" " + << "localName=\"" << localName << "\" " + << "qname=\"" << qname << "\")" << endl; + cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" << endl; + printDepth(); + cout << "<== BEGIN ATT LIST ==> " << endl; + printAttributes(atts); + printDepth(); + cout << "<== END ATT LIST ==> " << endl; + ++mDepth; + cout << "================================================" << endl; + } + + /*! + * Define end element method. Fired when a begin tag is found. + * \param name The name of the element tag + */ + void endElement(const std::string & uri, + const std::string & localName, + const std::string & qname) + { + printDepth(); + cout << "END ELEMENT " + << "(uri=\"" << uri << "\" " + << "localName=\"" << localName << "\" " + << "qname=\"" << qname << "\")" << endl; + cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" << endl; + cout << "================================================" << endl; + --mDepth; + } + +private: + + void printDepth() + { + for (int i = 0; i < mDepth; i++) + cout << ' '; + } + int mDepth; +}; + +// If I put in a streamTo() to an output stream, it works +// Otherwise it runs forever +int main(int argc, char **argv) +{ + try + { + // Check to make sure we have right length + if (argc != 2) + throw Exception(Ctxt(FmtX("Usage: %s \n", argv[0]))); + + // Create an input stream + FileInputStream + xmlFile(argv[1]); + + xml::lite::XMLReader xmlReader; + + std::cout << "XML Driver: " << xmlReader.getDriverName() << std::endl; + xmlReader.setContentHandler(new Reporter()); + + //EVAL( s.stream().str() ); + // Use the provided parse method to parse the input file + //xmlReporter.parse(s); + xmlReader.parse(xmlFile); + xmlFile.close(); + } + // Catch all throwables and exit in a reasonable manner + catch (Throwable & t) + { + cout << "Caught Throwable: " << t.toString() << endl; + + // If we caught an exception, exit unfavorably. + exit(EXIT_FAILURE); + } + return 0; +} +#else +int main() +{} +#endif + diff --git a/modules/c++/xml.lite/tests/large_benchmark1.xml b/modules/c++/xml.lite/tests/large_benchmark1.xml new file mode 100644 index 000000000..53e9cbe88 --- /dev/null +++ b/modules/c++/xml.lite/tests/large_benchmark1.xml @@ -0,0 +1,108775 @@ + + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + String + String + String + String + String + String + String + String + String + String + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + String + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + String + String + + + String + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + String + String + + + + Text + String + + String + + + + String + String + + String + + String + + String + String + String + + + String + + String + String + + + + Text + String + + String + + + + + String + String + + String + + String + + String + String + String + + + String + + String + String + + + + Text + String + + String + + + + String + + String + + String + String + String + + + String + + String + String + + + + Text + String + + String + + + String + String + + String + + diff --git a/modules/c++/xml.lite/tests/small_benchmark1.xml b/modules/c++/xml.lite/tests/small_benchmark1.xml new file mode 100644 index 000000000..6a656bd02 --- /dev/null +++ b/modules/c++/xml.lite/tests/small_benchmark1.xml @@ -0,0 +1,117 @@ + + + + + + String + String + + + String + String + + String + + String + + String + String + String + + + String + + String + String + + + + Text + String + + String + + + + + String + String + + String + + String + + String + String + String + + + String + + String + String + + + + Text + String + + String + + + + + String + String + + String + + String + + String + String + String + + + String + + String + String + + + + Text + String + + String + + + + String + + String + + String + String + String + + + String + + String + String + + + + Text + String + + String + + + String + String + + String + + diff --git a/modules/c++/xml.lite/tests/xmlrpc.com.request.soap b/modules/c++/xml.lite/tests/xmlrpc.com.request.soap new file mode 100644 index 000000000..1638de592 --- /dev/null +++ b/modules/c++/xml.lite/tests/xmlrpc.com.request.soap @@ -0,0 +1,11 @@ + + + + + 41 + + + diff --git a/modules/c++/xml.lite/wscript b/modules/c++/xml.lite/wscript new file mode 100644 index 000000000..2b5dbf69f --- /dev/null +++ b/modules/c++/xml.lite/wscript @@ -0,0 +1,12 @@ +NAME = 'xml.lite' +MAINTAINER = 'jmrandol@users.sourceforge.net' +VERSION = '1.2' +MODULE_DEPS = 'io mt logging' +USELIB_CHECK = 'XML' +TEST_FILTER = 'MMParserTest1.cpp MinidomParserTest2.cpp' +TEST_DEPS = 'io mt cli' + +options = configure = distclean = lambda p: None + +def build(bld): + bld.module(**globals()) diff --git a/modules/c/j2k/external/jasper/jasper-1.900.1-mod.tar b/modules/c/j2k/external/jasper/jasper-1.900.1-mod.tar new file mode 100644 index 000000000..5376c5956 Binary files /dev/null and b/modules/c/j2k/external/jasper/jasper-1.900.1-mod.tar differ diff --git a/modules/c/j2k/external/jasper/wscript b/modules/c/j2k/external/jasper/wscript new file mode 100644 index 000000000..77a25a999 --- /dev/null +++ b/modules/c/j2k/external/jasper/wscript @@ -0,0 +1,150 @@ +import os, sys +from os.path import join, exists +from waflib import Options +from waflib.TaskGen import feature, before, task_gen +from build import untarFile + +SOURCE = 'jasper-1.900.1-mod' +JASPER_DEFINES = ['USE_JASPER', 'HAVE_JASPER_H', 'J2K_MODULE_EXPORTS'] + +options = lambda x : None + +def configure(conf): + + j2kLayer = Options.options.j2k_layer + + if j2kLayer == 'jasper' : + + # NOTE: JasPer will compile in 64-bit mode, but it internally uses + # 32-bit integers for some offsets. To prevent confusion/badness, + # just don't allow it for a 64-bit build. + if conf.env['IS64BIT'] : + conf.msg('JPEG2000 library', 'jasper not available on 64-bit architectures', color='YELLOW') + return + + # add defines + conf.env.append_value('DEFINES_J2K', JASPER_DEFINES) + + conf.check_cc(header_name="sys/types.h", define_name='HAVE_SYS_TYPES_H') + uchar = conf.check_cc(type_name='uchar', header_name='sys/types.h', mandatory=False) + ushort = conf.check_cc(type_name='ushort', header_name='sys/types.h', mandatory=False) + longlong = conf.check_cc(type_name='longlong', header_name='sys/types.h', mandatory=False) + ulonglong = conf.check_cc(type_name='ulonglong', header_name='sys/types.h', mandatory=False) + + if not uchar: + conf.env.append_unique('jasper-defs', 'uchar=unsigned char') + if not ushort: + conf.env.append_unique('jasper-defs', 'ushort=unsigned short') + if not longlong: + conf.env.append_unique('jasper-defs', 'longlong=long long') + if not ulonglong: + conf.env.append_unique('jasper-defs', 'ulonglong=unsigned long long') + + # check for the source tarball + # TODO: I believe this file has some local mods and is not exactly + # the vanilla tarball - need to confirm + if not exists(join(conf.path.abspath(), SOURCE + '.tar')): + conf.fatal('Missing JasPer tarfile') + + # setup env + conf.env['MAKE_JASPER'] = True + conf.env['HAVE_J2K'] = True + conf.msg('Building local lib', j2kLayer) + untarFile(path=conf.path, fname=SOURCE + '.tar') + +def build(bld): + + env = bld.get_env() + sourceFiles = [] + + # check it again just in case + if 'MAKE_JASPER' in env : + jDefs = map(lambda x: x.split('='), env['jasper-defs']) + defDict = dict(PACKAGE='"jasper"', PACKAGE_NAME='"jasper"', + JAS_VERSION='"1.900.1"', PACKAGE_STRING='"jasper 1.900.1"', + PACKAGE_VERSION='"1.900.1"', PACKAGE_TARNAME='"jasper"', + VERSION='"1.900.1"',) + for k, v in jDefs: + defDict[k] = v + + configH = bld(name='config_h', output=join(SOURCE, 'include', 'jasper', 'jas_config.h'), + path=bld.path, defs=defDict, env=env.derive()) + configH.features = ['makeHeader'] + + jasperDefs = [] + if Options.platform.startswith('win'): + jasperDefs.append('JAS_WIN_MSVC_BUILD') + + includes = 'bmp include jp2 jpc jpg mif pgx pnm ras'.split() + sources = ( + 'bmp/bmp_cod.c', + 'bmp/bmp_dec.c', + 'bmp/bmp_enc.c', + 'base/jas_cm.c', + 'base/jas_debug.c', + 'base/jas_getopt.c', + 'base/jas_icc.c', + 'base/jas_iccdata.c', + 'base/jas_image.c', + 'base/jas_init.c', + 'base/jas_malloc.c', + 'base/jas_seq.c', + 'base/jas_stream.c', + 'base/jas_string.c', + 'base/jas_tmr.c', + 'base/jas_tvp.c', + 'base/jas_version.c', + 'jp2/jp2_cod.c', + 'jp2/jp2_dec.c', + 'jp2/jp2_enc.c', + 'jpc/jpc_bs.c', + 'jpc/jpc_cs.c', + 'jpc/jpc_dec.c', + 'jpc/jpc_enc.c', + 'jpc/jpc_math.c', + 'jpc/jpc_mct.c', + 'jpc/jpc_mqcod.c', + 'jpc/jpc_mqdec.c', + 'jpc/jpc_mqenc.c', + 'jpc/jpc_qmfb.c', + 'jpc/jpc_t1cod.c', + 'jpc/jpc_t1dec.c', + 'jpc/jpc_t1enc.c', + 'jpc/jpc_t2cod.c', + 'jpc/jpc_t2dec.c', + 'jpc/jpc_t2enc.c', + 'jpc/jpc_tagtree.c', + 'jpc/jpc_tsfb.c', + 'jpc/jpc_util.c', + 'jpg/jpg_dummy.c', + 'jpg/jpg_val.c', + 'mif/mif_cod.c', + 'pgx/pgx_cod.c', + 'pgx/pgx_dec.c', + 'pgx/pgx_enc.c', + 'pnm/pnm_cod.c', + 'pnm/pnm_dec.c', + 'pnm/pnm_enc.c', + 'ras/ras_cod.c', + 'ras/ras_dec.c', + 'ras/ras_enc.c', + ) + + jasper = bld(features='c cstlib add_targets', includes=includes, + source=sources, + target='jasper', + name='jasper', + export_includes='include', + defines=env['DEFINES'] + jasperDefs, + targets_to_add='config_h', + env=env.derive(), + path=bld.path.make_node(SOURCE)) + + # install lib + if env['install_libs']: + jasper.install_path = env['install_libdir'] + + # TODO: install headers + +def distclean(context): + pass diff --git a/modules/c/j2k/external/openjpeg/openjpeg-2.0.0.tar b/modules/c/j2k/external/openjpeg/openjpeg-2.0.0.tar new file mode 100644 index 000000000..f67dfddeb Binary files /dev/null and b/modules/c/j2k/external/openjpeg/openjpeg-2.0.0.tar differ diff --git a/modules/c/j2k/external/openjpeg/wscript b/modules/c/j2k/external/openjpeg/wscript new file mode 100644 index 000000000..0d5bda389 --- /dev/null +++ b/modules/c/j2k/external/openjpeg/wscript @@ -0,0 +1,127 @@ +import os, sys +from os.path import join, exists +from waflib import Options +from waflib.TaskGen import feature, before, task_gen +from build import untarFile + +SOURCE = 'openjpeg-2.0.0' +OPENJPEG_DEFINES = ['USE_OPENJPEG', 'HAVE_OPENJPEG_H', 'J2K_MODULE_EXPORTS'] +STATIC_DEFINE = 'OPJ_STATIC' + +options = lambda x : None + +def configure(conf): + + j2kLayer = Options.options.j2k_layer + + if j2kLayer == 'openjpeg' : + + # add defines + defines = OPENJPEG_DEFINES + if not Options.options.shared_libs: + defines.append(STATIC_DEFINE) + conf.env.append_value('DEFINES_J2K', defines) + + # check functionality + check1 = conf.check_cc(function_name='fseeko', header_name="stdio.h", mandatory=False) + conf.check_cc(header_name="stdint.h", mandatory=False) + conf.check_cc(header_name="sys/stat.h", mandatory=False) + conf.check_cc(header_name="sys/types.h", mandatory=False) + + # check for the source tarball + if not exists(join(conf.path.abspath(), SOURCE + '.tar')): + conf.fatal('Missing OpenJPEG tarfile') + + # untar and setup env + conf.env['MAKE_OPENJPEG'] = True + conf.env['HAVE_J2K'] = True + conf.msg('Building local lib', j2kLayer) + untarFile(path=conf.path, fname=SOURCE + '.tar') + +def build(bld): + + env = bld.get_env() + sourceFiles = [] + + # check it again just in case + if 'MAKE_OPENJPEG' in env: + # this node is a mandatory build -- others are optional + openjpegNode = bld.path.make_node(join(SOURCE, 'src', 'lib', 'openjp2')) + + # make opj_config.h + defs = {} + headers = 'INTTYPES MEMORY STDINT STDLIB STRINGS STRING SYS_STAT SYS_TYPES UNISTD'.split() + + for header in headers: + define = 'HAVE_' + header + '_H' + if (define + '=1') in env['DEFINES']: + defs[define] = '' + + if 'HAVE_SSIZE_T=1' in env['DEFINES']: + defs['HAVE_SSIZE_T'] = '' + + if '_LARGEFILE_SOURCE' in env['DEFINES']: + defs['_LARGEFILE_SOURCE'] = '' + if '_LARGEFILES' in env['DEFINES']: + defs['_LARGEFILES'] = '' + if '_FILE_OFFSET_BITS=64' in env['DEFINES']: + defs['_FILE_OFFSET_BITS'] = '64' + + if 'HAVE_FSEEKO=1' in env['DEFINES']: + defs['HAVE_FSEEKO'] = '' + + defs['OPJ_PACKAGE_VERSION'] = '"2.0.0"' + if sys.byteorder != 'little': + defs['OPJ_BIG_ENDIAN'] = '' + + openjpegConfigH = bld(name='openjpegConfigH', + features='makeHeader', + output='opj_config.h', + path=openjpegNode, + defs=defs, + guard='__OPJ_CONFIG_H__', + env=env.derive()) + + # build the lib + sources = ['bio.c', 'cio.c', 'dwt.c', 'event.c', 'image.c', + 'invert.c', 'j2k.c', 'jp2.c', 'mct.c', 'mqc.c', + 'openjpeg.c', 'opj_clock.c', 'pi.c', 'raw.c', + 't1.c', 't2.c', 'tcd.c', 'tgt.c', 'function_list.c'] + + libType = env['LIB_TYPE'] or 'stlib' + defines = [] + if libType == 'stlib': + defines.append(STATIC_DEFINE) + + openjpeg = bld(features='c c%s add_targets' % libType, + includes='.', export_includes='.', + source=sources, target='openjpeg', name='openjpeg', + defines=defines, + path=openjpegNode, env=env.derive(), targets_to_add=[openjpegConfigH]) + + # install lib + if env['install_libs']: + openjpeg.install_path = env['install_libdir'] + + # install headers + if env['install_headers']: + openjpeg.targets_to_add.append( + bld(features='install_tgt', + includes='openjpeg.h opj_stdint.h opj_config.h', + dir=openjpegNode, install_path=env['install_includedir'], + name='J2K_INCLUDES_INSTALL')) + + +def distclean(context): + + # remove the untarred directories + import shutil + + dirs = filter(lambda x: exists(join(context.path.abspath(), x)), + [SOURCE]) + + for d in dirs: + try: + shutil.rmtree(join(context.path.abspath(), d), ignore_errors=True) + except:{} + diff --git a/modules/c/j2k/include/import/j2k.h b/modules/c/j2k/include/import/j2k.h new file mode 100644 index 000000000..836cce942 --- /dev/null +++ b/modules/c/j2k/include/import/j2k.h @@ -0,0 +1,31 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __IMPORT_J2K_H__ +#define __IMPORT_J2K_H__ + +#include "j2k/Container.h" +#include "j2k/Defines.h" +#include "j2k/Reader.h" +#include "j2k/Writer.h" + +#endif diff --git a/modules/c/j2k/include/j2k/Component.h b/modules/c/j2k/include/j2k/Component.h new file mode 100644 index 000000000..dc1f9ec3c --- /dev/null +++ b/modules/c/j2k/include/j2k/Component.h @@ -0,0 +1,119 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __J2K_COMPONENT_H__ +#define __J2K_COMPONENT_H__ + +#include "j2k/Defines.h" + +J2K_CXX_GUARD + +typedef nrt_Uint32 (*J2K_ICOMPONENT_GET_WIDTH)(J2K_USER_DATA*, nrt_Error*); +typedef nrt_Uint32 (*J2K_ICOMPONENT_GET_HEIGHT)(J2K_USER_DATA*, nrt_Error*); +typedef nrt_Uint32 (*J2K_ICOMPONENT_GET_PRECISION)(J2K_USER_DATA*, nrt_Error*); +typedef NRT_BOOL (*J2K_ICOMPONENT_IS_SIGNED)(J2K_USER_DATA*, nrt_Error*); +typedef nrt_Int32 (*J2K_ICOMPONENT_GET_OFFSET_X)(J2K_USER_DATA*, nrt_Error*); +typedef nrt_Int32 (*J2K_ICOMPONENT_GET_OFFSET_Y)(J2K_USER_DATA*, nrt_Error*); +typedef nrt_Uint32 (*J2K_ICOMPONENT_GET_SEPARATION_X)(J2K_USER_DATA*, nrt_Error*); +typedef nrt_Uint32 (*J2K_ICOMPONENT_GET_SEPARATION_Y)(J2K_USER_DATA*, nrt_Error*); +typedef void (*J2K_ICOMPONENT_DESTRUCT)(J2K_USER_DATA *); + +typedef struct _j2k_IComponent +{ + J2K_ICOMPONENT_GET_WIDTH getWidth; + J2K_ICOMPONENT_GET_HEIGHT getHeight; + J2K_ICOMPONENT_GET_PRECISION getPrecision; + J2K_ICOMPONENT_IS_SIGNED isSigned; + J2K_ICOMPONENT_GET_OFFSET_X getOffsetX; + J2K_ICOMPONENT_GET_OFFSET_Y getOffsetY; + J2K_ICOMPONENT_GET_SEPARATION_X getSeparationX; + J2K_ICOMPONENT_GET_SEPARATION_Y getSeparationY; + J2K_ICOMPONENT_DESTRUCT destruct; +} j2k_IComponent; + +typedef struct _j2k_Component +{ + j2k_IComponent *iface; + J2K_USER_DATA *data; +} j2k_Component; + +/** + * Constructs a Component from scratch using the provided metadata + */ +J2KAPI(j2k_Component*) j2k_Component_construct(nrt_Uint32 width, + nrt_Uint32 height, + nrt_Uint32 precision, + NRT_BOOL isSigned, + nrt_Uint32 offsetX, + nrt_Uint32 offsetY, + nrt_Uint32 separationX, + nrt_Uint32 separationY, + nrt_Error *error); + +/** + * Returns the width of the Component + */ +J2KAPI(nrt_Uint32) j2k_Component_getWidth(j2k_Component*, nrt_Error*); + +/** + * Returns the height of the Component + */ +J2KAPI(nrt_Uint32) j2k_Component_getHeight(j2k_Component*, nrt_Error*); + +/** + * Returns the number of bits per sample per component + */ +J2KAPI(nrt_Uint32) j2k_Component_getPrecision(j2k_Component*, nrt_Error*); + +/** + * Returns whether the data is signed + */ +J2KAPI(NRT_BOOL) j2k_Component_isSigned(j2k_Component*, nrt_Error*); + +/** + * Returns the X offset into the reference grid + */ +J2KAPI(nrt_Int32) j2k_Component_getOffsetX(j2k_Component*, nrt_Error*); + +/** + * Returns the Y offset into the reference grid + */ +J2KAPI(nrt_Int32) j2k_Component_getOffsetY(j2k_Component*, nrt_Error*); + +/** + * Returns the width separation between samples on the reference grid + */ +J2KAPI(nrt_Uint32) j2k_Component_getSeparationX(j2k_Component*, nrt_Error*); + +/** + * Returns the height separation between samples on the reference grid + */ +J2KAPI(nrt_Uint32) j2k_Component_getSeparationY(j2k_Component*, nrt_Error*); + +/** + * Destroys the Component + */ +J2KAPI(void) j2k_Component_destruct(j2k_Component**); + +J2K_CXX_ENDGUARD + +#endif diff --git a/modules/c/j2k/include/j2k/Container.h b/modules/c/j2k/include/j2k/Container.h new file mode 100644 index 000000000..e228e5c6b --- /dev/null +++ b/modules/c/j2k/include/j2k/Container.h @@ -0,0 +1,143 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __J2K_CONTAINER_H__ +#define __J2K_CONTAINER_H__ + +#include "j2k/Defines.h" +#include "j2k/Component.h" + +J2K_CXX_GUARD + +typedef nrt_Uint32 (*J2K_ICONTAINER_GET_GRID_WIDTH)(J2K_USER_DATA*, nrt_Error*); +typedef nrt_Uint32 (*J2K_ICONTAINER_GET_GRID_HEIGHT)(J2K_USER_DATA*, nrt_Error*); +typedef nrt_Uint32 (*J2K_ICONTAINER_GET_NUM_COMPONENTS)(J2K_USER_DATA*, nrt_Error*); +typedef j2k_Component* (*J2K_ICONTAINER_GET_COMPONENT)(J2K_USER_DATA*, nrt_Uint32, nrt_Error*); +typedef nrt_Uint32 (*J2K_ICONTAINER_GET_TILESX)(J2K_USER_DATA*, nrt_Error*); +typedef nrt_Uint32 (*J2K_ICONTAINER_GET_TILESY)(J2K_USER_DATA*, nrt_Error*); +typedef nrt_Uint32 (*J2K_ICONTAINER_GET_TILE_WIDTH)(J2K_USER_DATA*, nrt_Error*); +typedef nrt_Uint32 (*J2K_ICONTAINER_GET_TILE_HEIGHT)(J2K_USER_DATA*, nrt_Error*); +typedef int (*J2K_ICONTAINER_GET_IMAGE_TYPE)(J2K_USER_DATA*, nrt_Error*); +typedef void (*J2K_ICONTAINER_DESTRUCT)(J2K_USER_DATA *); + +typedef struct _j2k_IContainer +{ + J2K_ICONTAINER_GET_GRID_WIDTH getGridWidth; + J2K_ICONTAINER_GET_GRID_HEIGHT getGridHeight; + J2K_ICONTAINER_GET_NUM_COMPONENTS getNumComponents; + J2K_ICONTAINER_GET_COMPONENT getComponent; + + J2K_ICONTAINER_GET_TILESX getTilesX; + J2K_ICONTAINER_GET_TILESY getTilesY; + J2K_ICONTAINER_GET_TILE_WIDTH getTileWidth; + J2K_ICONTAINER_GET_TILE_HEIGHT getTileHeight; + + J2K_ICONTAINER_GET_IMAGE_TYPE getImageType; + J2K_ICONTAINER_DESTRUCT destruct; +} j2k_IContainer; + +typedef struct _j2k_Container +{ + j2k_IContainer *iface; + J2K_USER_DATA *data; +} j2k_Container; + +/** + * Constructs a Container from scratch using the provided metadata + */ +J2KAPI(j2k_Container*) j2k_Container_construct(nrt_Uint32 gridWidth, + nrt_Uint32 gridHeight, + nrt_Uint32 numComponents, + j2k_Component** components, + nrt_Uint32 tileWidth, + nrt_Uint32 tileHeight, + int imageType, + nrt_Error *error); + +/** + * Returns the reference grid width + */ +J2KAPI(nrt_Uint32) j2k_Container_getGridWidth(j2k_Container*, nrt_Error*); + +/** + * Returns the reference grid height + */ +J2KAPI(nrt_Uint32) j2k_Container_getGridHeight(j2k_Container*, nrt_Error*); + +/** + * Returns the number of components/bands + */ +J2KAPI(nrt_Uint32) j2k_Container_getNumComponents(j2k_Container*, nrt_Error*); + +/** + * Returns the i'th Component + */ +J2KAPI(j2k_Component*) j2k_Container_getComponent(j2k_Container*, nrt_Uint32, nrt_Error*); + +/** + * Returns the actual image width (in samples) - i.e. the max component width + */ +J2KAPI(nrt_Uint32) j2k_Container_getWidth(j2k_Container*, nrt_Error*); + +/** + * Returns the actual image height (in samples) - i.e. the max component height + */ +J2KAPI(nrt_Uint32) j2k_Container_getHeight(j2k_Container*, nrt_Error*); + +/** + * Returns the max component precision + */ +J2KAPI(nrt_Uint32) j2k_Container_getPrecision(j2k_Container*, nrt_Error*); + +/** + * Returns the number of column tiles (X-direction) + */ +J2KAPI(nrt_Uint32) j2k_Container_getTilesX(j2k_Container*, nrt_Error*); + +/** + * Returns the number of row tiles (Y-direction) + */ +J2KAPI(nrt_Uint32) j2k_Container_getTilesY(j2k_Container*, nrt_Error*); + +/** + * Returns the tile width + */ +J2KAPI(nrt_Uint32) j2k_Container_getTileWidth(j2k_Container*, nrt_Error*); + +/** + * Returns the tile height + */ +J2KAPI(nrt_Uint32) j2k_Container_getTileHeight(j2k_Container*, nrt_Error*); + +/** + * Returns the image type + */ +J2KAPI(int) j2k_Container_getImageType(j2k_Container*, nrt_Error*); + +/** + * Destroys the Container + */ +J2KAPI(void) j2k_Container_destruct(j2k_Container**); + +J2K_CXX_ENDGUARD + +#endif diff --git a/modules/c/j2k/include/j2k/Defines.h b/modules/c/j2k/include/j2k/Defines.h new file mode 100644 index 000000000..f89b0a879 --- /dev/null +++ b/modules/c/j2k/include/j2k/Defines.h @@ -0,0 +1,68 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __J2K_DEFINES_H__ +#define __J2K_DEFINES_H__ + + +#ifdef WIN32 +# if defined(J2K_MODULE_EXPORTS) +# define NRT_MODULE_EXPORTS +# elif defined(J2K_MODULE_IMPORTS) +# define NRT_MODULE_IMPORTS +# endif +#endif + +#include + +#define J2K_C NRT_C +#define J2K_GUARD NRT_GUARD +#define J2K_ENDGUARD NRT_ENDGUARD +#define J2K_BOOL NRT_BOOL +#define J2KAPI(RT) NRTAPI(RT) +#define J2KPROT(RT) NRTPROT(RT) +#define J2K_CXX_GUARD NRT_CXX_GUARD +#define J2K_CXX_ENDGUARD NRT_CXX_ENDGUARD +#define J2KPRIV NRTPRIV +#define J2K_FILE NRT_FILE +#define J2K_LINE NRT_LINE +#define J2K_FUNC NRT_FUNC + +#define J2K_MALLOC NRT_MALLOC +#define J2K_REALLOC NRT_REALLOC +#define J2K_FREE NRT_FREE + +#define J2K_SUCCESS NRT_SUCCESS +#define J2K_FAILURE NRT_FAILURE +#define J2K_TRUE NRT_TRUE +#define J2K_FALSE NRT_FALSE + +typedef NRT_DATA J2K_USER_DATA; + +typedef enum _j2k_ImageType +{ + J2K_TYPE_UNKNOWN = 0, + J2K_TYPE_MONO, + J2K_TYPE_RGB +} j2k_ImageType; + +#endif diff --git a/modules/c/j2k/include/j2k/Reader.h b/modules/c/j2k/include/j2k/Reader.h new file mode 100644 index 000000000..d189be688 --- /dev/null +++ b/modules/c/j2k/include/j2k/Reader.h @@ -0,0 +1,98 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __J2K_READER_H__ +#define __J2K_READER_H__ + +#include "j2k/Container.h" + +J2K_CXX_GUARD + +typedef J2K_BOOL (*J2K_IREADER_CAN_READ_TILES)(J2K_USER_DATA*, nrt_Error*); +typedef nrt_Uint64 (*J2K_IREADER_READ_TILE)(J2K_USER_DATA*, nrt_Uint32 tileX, + nrt_Uint32 tileY, nrt_Uint8 **buf, + nrt_Error*); +typedef nrt_Uint64 (*J2K_IREADER_READ_REGION)(J2K_USER_DATA*, nrt_Uint32 x0, + nrt_Uint32 y0, nrt_Uint32 x1, + nrt_Uint32 y1, nrt_Uint8 **buf, + nrt_Error*); +typedef j2k_Container* (*J2K_IREADER_GET_CONTAINER)(J2K_USER_DATA*, nrt_Error*); +typedef void (*J2K_IREADER_DESTRUCT)(J2K_USER_DATA *); + +typedef struct _j2k_IReader +{ + J2K_IREADER_CAN_READ_TILES canReadTiles; + J2K_IREADER_READ_TILE readTile; + J2K_IREADER_READ_REGION readRegion; + J2K_IREADER_GET_CONTAINER getContainer; + J2K_IREADER_DESTRUCT destruct; +} j2k_IReader; + +typedef struct _j2k_Reader +{ + j2k_IReader *iface; + J2K_USER_DATA *data; +} j2k_Reader; + +/** + * Opens a J2K Container from an IOInterface + */ +J2KAPI(j2k_Reader*) j2k_Reader_openIO(nrt_IOInterface*, nrt_Error*); + +/** + * Opens a J2K Container from a file on disk. + */ +J2KAPI(j2k_Reader*) j2k_Reader_open(const char*, nrt_Error*); + +/** + * Declares whether or not the reader can read individual tiles + */ +J2KAPI(J2K_BOOL) j2k_Reader_canReadTiles(j2k_Reader*, nrt_Error*); + +/** + * Reads an individual tile at the given indices + */ +J2KAPI(nrt_Uint64) j2k_Reader_readTile(j2k_Reader*, nrt_Uint32 tileX, + nrt_Uint32 tileY, nrt_Uint8 **buf, + nrt_Error*); + +/** + * Reads image data from the desired region + */ +J2KAPI(nrt_Uint64) j2k_Reader_readRegion(j2k_Reader*, nrt_Uint32 x0, + nrt_Uint32 y0, nrt_Uint32 x1, + nrt_Uint32 y1, nrt_Uint8 **buf, + nrt_Error*); + +/** + * Returns the associated container (the Reader will still own it) + */ +J2KAPI(j2k_Container*) j2k_Reader_getContainer(j2k_Reader*, nrt_Error*); + +/** + * Destroys the Reader object + */ +J2KAPI(void) j2k_Reader_destruct(j2k_Reader**); + +J2K_CXX_ENDGUARD + +#endif diff --git a/modules/c/j2k/include/j2k/Writer.h b/modules/c/j2k/include/j2k/Writer.h new file mode 100644 index 000000000..c5ec87902 --- /dev/null +++ b/modules/c/j2k/include/j2k/Writer.h @@ -0,0 +1,94 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __J2K_WRITER_H__ +#define __J2K_WRITER_H__ + +#include "j2k/Container.h" + +J2K_CXX_GUARD + +typedef J2K_BOOL (*J2K_IWRITER_SET_TILE)(J2K_USER_DATA*, nrt_Uint32, + nrt_Uint32, const nrt_Uint8 *, + nrt_Uint32, nrt_Error*); +typedef J2K_BOOL (*J2K_IWRITER_WRITE)(J2K_USER_DATA*, nrt_IOInterface*, + nrt_Error*); +typedef j2k_Container* (*J2K_IWRITER_GET_CONTAINER)(J2K_USER_DATA*, nrt_Error*); +typedef void (*J2K_IWRITER_DESTRUCT)(J2K_USER_DATA *); + +typedef struct _j2k_IWriter +{ + J2K_IWRITER_SET_TILE setTile; + J2K_IWRITER_WRITE write; + J2K_IWRITER_GET_CONTAINER getContainer; + J2K_IWRITER_DESTRUCT destruct; +} j2k_IWriter; + +typedef struct _j2k_WriterOptions +{ + /* TODO add more options as we see fit */ + double compressionRatio; + nrt_Uint32 numResolutions; +} j2k_WriterOptions; + +typedef struct _j2k_Writer +{ + j2k_IWriter *iface; + J2K_USER_DATA *data; +} j2k_Writer; + +J2KAPI(NRT_BOOL) j2k_Writer_setOptions(j2k_WriterOptions* options, + nrt_HashTable* userOptions, + nrt_Error* error); +/** + * Opens a J2K Container from an IOInterface + */ +J2KAPI(j2k_Writer*) j2k_Writer_construct(j2k_Container*, j2k_WriterOptions*, + nrt_Error*); + +/** + * Sets the uncompressed data for the tile at the given indices. + * It is assumed that the passed-in buffer will be available for deletion + * immediately after the call returns. + */ +J2KAPI(J2K_BOOL) j2k_Writer_setTile(j2k_Writer*, nrt_Uint32 tileX, + nrt_Uint32 tileY, const nrt_Uint8 *buf, + nrt_Uint32 bufSize, nrt_Error*); + +/** + * Writes to the IOInterface + */ +J2KAPI(J2K_BOOL) j2k_Writer_write(j2k_Writer*, nrt_IOInterface*, nrt_Error*); + +/** + * Returns the associated container + */ +J2KAPI(j2k_Container*) j2k_Writer_getContainer(j2k_Writer*, nrt_Error*); + +/** + * Destroys the Writer object + */ +J2KAPI(void) j2k_Writer_destruct(j2k_Writer**); + +J2K_CXX_ENDGUARD + +#endif diff --git a/modules/c/j2k/shared/J2KCompress.c b/modules/c/j2k/shared/J2KCompress.c new file mode 100644 index 000000000..d0a8e1f39 --- /dev/null +++ b/modules/c/j2k/shared/J2KCompress.c @@ -0,0 +1,453 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifdef HAVE_J2K_H + +#include +#include + +NITF_CXX_GUARD + +NITFPRIV(nitf_CompressionControl*) implOpen(nitf_ImageSubheader*, nrt_HashTable*, nitf_Error*); + +NITFPRIV(NITF_BOOL) implStart(nitf_CompressionControl *control, + nitf_Uint64 offset, + nitf_Uint64 dataLength, + nitf_Uint64 *blockMask, + nitf_Uint64 *padMask, + nitf_Error *error); + +NITFPRIV(NITF_BOOL) implWriteBlock(nitf_CompressionControl * control, + nitf_IOInterface *io, + const nitf_Uint8 *data, + NITF_BOOL pad, + NITF_BOOL noData, + nitf_Error *error); + +NITFPRIV(NITF_BOOL) implEnd( nitf_CompressionControl * control, + nitf_IOInterface *io, + nitf_Error *error); + +NITFPRIV(void) implDestroy(nitf_CompressionControl ** control); + + +static const char *ident[] = +{ + NITF_PLUGIN_COMPRESSION_KEY, "C8", NULL +}; + +static nitf_CompressionInterface interfaceTable = +{ + implOpen, implStart, implWriteBlock, implEnd, implDestroy, NULL +}; + +typedef struct _ImplControl +{ + nitf_BlockingInfo blockInfo; /* Kept for convenience */ + j2k_Container *container; /* j2k Container */ + j2k_Writer *writer; /* j2k Writer */ + nitf_Uint64 offset; + nitf_Uint64 dataLength; + nitf_Uint32 curBlock; + nitf_Field *comratField; /* kept so we can update it */ +}ImplControl; + +NITF_CXX_ENDGUARD + + +NITFAPI(const char**) J2KCompress_init(nitf_Error *error) +{ + return ident; +} + +NITFAPI(void) C8_cleanup(void) +{ + /* TODO */ +} + + +NITFAPI(void*) C8_construct(char *compressionType, + nitf_Error* error) +{ + if (strcmp(compressionType, "C8") != 0) + { + nitf_Error_init(error, + "Unsupported compression type", + NITF_CTXT, + NITF_ERR_DECOMPRESSION); + + return NULL; + } + return((void *) &interfaceTable); +} + + +NITFPRIV(nitf_CompressionControl*) implOpen(nitf_ImageSubheader *subheader, + nrt_HashTable* userOptions, + nitf_Error *error) +{ + ImplControl *implControl = NULL; + j2k_Component **components = NULL; + j2k_WriterOptions options; + + nitf_Uint32 nRows; + nitf_Uint32 nCols; + nitf_Uint32 nBands; + nitf_Uint32 nbpp; + nitf_Uint32 abpp; + nitf_Uint32 nbpr; + nitf_Uint32 nbpc; + nitf_Uint32 nppbh; + nitf_Uint32 nppbv; + char pvtype[NITF_PVTYPE_SZ+1]; + char ic[NITF_IC_SZ+1]; + //char comrat[NITF_COMRAT_SZ+1]; + char imode[NITF_IMODE_SZ+1]; + char irep[NITF_IREP_SZ+1]; + int imageType; + J2K_BOOL isSigned = 0; + nrt_Uint32 idx; + + /* reset the options */ + memset(&options, 0, sizeof(j2k_WriterOptions)); + if(userOptions) + { + if(!j2k_Writer_setOptions(&options, userOptions, error)) + goto CATCH_ERROR; + } + + if(!nitf_Field_get(subheader->NITF_NROWS, &nRows, + NITF_CONV_INT, sizeof(nitf_Uint32), error)) + { + goto CATCH_ERROR; + } + if(!nitf_Field_get(subheader->NITF_NCOLS, &nCols, + NITF_CONV_INT, sizeof(nitf_Uint32), error)) + { + goto CATCH_ERROR; + } + + if (0 == (nBands = nitf_ImageSubheader_getBandCount(subheader, error))) + { + goto CATCH_ERROR; + } + + if(!nitf_Field_get(subheader->NITF_NBPP, &nbpp, + NITF_CONV_INT, sizeof(nitf_Uint32), error)) + { + goto CATCH_ERROR; + } + if(!nitf_Field_get(subheader->NITF_ABPP, &abpp, + NITF_CONV_INT, sizeof(nitf_Uint32), error)) + { + goto CATCH_ERROR; + } + if(!nitf_Field_get(subheader->NITF_NPPBH, &nppbh, + NITF_CONV_INT, sizeof(nitf_Uint32), error)) + { + goto CATCH_ERROR; + } + if(!nitf_Field_get(subheader->NITF_NPPBV, &nppbv, + NITF_CONV_INT, sizeof(nitf_Uint32), error)) + { + goto CATCH_ERROR; + } + if(!nitf_Field_get(subheader->NITF_NBPR, &nbpr, + NITF_CONV_INT, sizeof(nitf_Uint32), error)) + { + goto CATCH_ERROR; + } + if(!nitf_Field_get(subheader->NITF_NBPC, &nbpc, + NITF_CONV_INT, sizeof(nitf_Uint32), error)) + { + goto CATCH_ERROR; + } + + if(!nitf_Field_get(subheader->NITF_IREP, irep, NITF_CONV_STRING, + NITF_IREP_SZ+1, error)) + { + goto CATCH_ERROR; + } + if(!nitf_Field_get(subheader->NITF_PVTYPE, pvtype, NITF_CONV_STRING, + NITF_PVTYPE_SZ+1, error)) + { + goto CATCH_ERROR; + } + if(!nitf_Field_get(subheader->NITF_IC, ic, NITF_CONV_STRING, + NITF_IC_SZ+1, error)) + { + goto CATCH_ERROR; + } + /*if(!nitf_Field_get(subheader->NITF_COMRAT, comrat, NITF_CONV_STRING, + NITF_COMRAT_SZ+1, error)) + { + goto CATCH_ERROR; + }*/ + if(!nitf_Field_get(subheader->NITF_IMODE, imode, NITF_CONV_STRING, + NITF_IMODE_SZ+1, error)) + { + goto CATCH_ERROR; + } + + nitf_Field_trimString(pvtype); + if(strcmp(pvtype, "INT") != 0 && strcmp(pvtype, "SI") != 0 + && strcmp(pvtype, "B") != 0) + { + nitf_Error_init(error, + "For J2k compression, PVTYPE must be INT, SI or B", + NITF_CTXT, NITF_ERR_COMPRESSION); + goto CATCH_ERROR; + } + if (strcmp(pvtype, "SI") == 0) + { + isSigned = J2K_TRUE; + } + + nitf_Field_trimString(imode); + if(strcmp(imode, "B") != 0) + { + nitf_Error_init(error, + "For J2k compression, IMODE must be B", + NITF_CTXT, NITF_ERR_INVALID_OBJECT); + goto CATCH_ERROR; + } + + nitf_Field_trimString(ic); + if(strcmp(ic, "C8") != 0) + { + nitf_Error_init(error, + "For J2k compression, IC must be C8", + NITF_CTXT, NITF_ERR_COMPRESSION); + goto CATCH_ERROR; + } + + /*nitf_Field_trimString(comrat); + if(strlen(comrat) != 0) + { + if (comrat[0] == 'N') + { + // numerically lossless + double bitRate = NITF_ATO32(&comrat[1]) / 10.0; + options.compressionRatio = bitRate / abpp; + } + }*/ + + nitf_Field_trimString(irep); + if (strcmp(irep, "RGB") == 0) + { + if (nBands < 3) + { + nitf_Error_init(error, + "For RGB irep, must have at least 3 bands", + NITF_CTXT, NITF_ERR_COMPRESSION); + goto CATCH_ERROR; + } + imageType = J2K_TYPE_RGB; + } + else if (strcmp(irep, "RGB/LUT") == 0) + { + nitf_Error_init(error, + "RGB/LUT not yet supported", + NITF_CTXT, NITF_ERR_COMPRESSION); + goto CATCH_ERROR; + } + else + { + /* TODO should be named J2K_TYPE_GRAY */ + imageType = J2K_TYPE_MONO; + } + + if (!(implControl = (ImplControl*)NITF_MALLOC(sizeof(ImplControl)))) + { + nitf_Error_init(error, NITF_STRERROR( NITF_ERRNO ), + NITF_CTXT, NITF_ERR_MEMORY); + goto CATCH_ERROR; + } + memset(implControl, 0, sizeof(ImplControl)); + + implControl->comratField = subheader->NITF_COMRAT; + + /* initialize the container */ + if (!(components = (j2k_Component**)J2K_MALLOC( + sizeof(j2k_Component*) * nBands))) + { + nrt_Error_init(error, NRT_STRERROR(NRT_ERRNO), NRT_CTXT, + NRT_ERR_MEMORY); + goto CATCH_ERROR; + } + + for(idx = 0; idx < nBands; ++idx) + { + if (!(components[idx] = j2k_Component_construct(nCols, nRows, abpp, + isSigned, 0, 0, 1, 1, + error))) + { + goto CATCH_ERROR; + } + } + + if (!(implControl->container = j2k_Container_construct(nCols, + nRows, + nBands, + components, + nppbh, + nppbv, + imageType, + error))) + { + goto CATCH_ERROR; + } + + if (!(implControl->writer = j2k_Writer_construct(implControl->container, + &options, error))) + { + goto CATCH_ERROR; + } + + return((nitf_CompressionControl*) implControl); + + CATCH_ERROR: + { + if(implControl) + { + implDestroy((nitf_CompressionControl **)&implControl); + } + return NULL; + } +} + +NITFPRIV(NITF_BOOL) implStart(nitf_CompressionControl *control, + nitf_Uint64 offset, + nitf_Uint64 dataLength, + nitf_Uint64 *blockMask, + nitf_Uint64 *padMask, + nitf_Error *error) +{ + ImplControl *implControl = (ImplControl*)control; + + implControl->offset = offset; + implControl->dataLength = dataLength; + implControl->curBlock = 0; + + return NITF_SUCCESS; +} + +NITFPRIV(NITF_BOOL) implWriteBlock(nitf_CompressionControl * control, + nitf_IOInterface *io, + const nitf_Uint8 *data, + NITF_BOOL pad, + NITF_BOOL noData, + nitf_Error *error) +{ + ImplControl *implControl = (ImplControl*)control; + nitf_Uint32 tileX, tileY, tileWidth, tileHeight, tilesX; + nitf_Uint32 nComponents, nBytes, bufSize; + + /* TODO this needs to change... won't work on separated images */ + tileWidth = j2k_Container_getTileWidth(implControl->container, error); + tileHeight = j2k_Container_getTileHeight(implControl->container, error); + tilesX = j2k_Container_getTilesX(implControl->container, error); + nComponents = j2k_Container_getNumComponents(implControl->container, error); + nBytes = (j2k_Container_getPrecision(implControl->container, error) - 1) / 8 + 1; + + tileX = implControl->curBlock % tilesX; + tileY = implControl->curBlock / tilesX; + bufSize = tileWidth * tileHeight * nComponents * nBytes; + + if (!j2k_Writer_setTile(implControl->writer, tileX, tileY, data, bufSize, + error)) + { + goto CATCH_ERROR; + } + implControl->curBlock++; + return NITF_SUCCESS; + + CATCH_ERROR: + { + return NITF_FAILURE; + } +} + +NITFPRIV(NITF_BOOL) implEnd( nitf_CompressionControl * control, + nitf_IOInterface *io, + nitf_Error *error) +{ + ImplControl *implControl = (ImplControl*)control; + nitf_Off offset; + size_t compressedSize, rawSize; + nitf_Uint32 comratInt; + float comrat; + nitf_Uint32 width, height, nComponents, nBytes, nBits; + + width = j2k_Container_getWidth(implControl->container, error); + height = j2k_Container_getHeight(implControl->container, error); + nComponents = j2k_Container_getNumComponents(implControl->container, error); + nBits = j2k_Container_getPrecision(implControl->container, error); + + nBytes = (nBits - 1) / 8 + 1; + + offset = nitf_IOInterface_tell(io, error); + + if (!j2k_Writer_write(implControl->writer, io, error)) + return NITF_FAILURE; + + /* figure out the compression ratio */ + compressedSize = (size_t)(nitf_IOInterface_tell(io, error) - offset); + rawSize = (size_t)width * height * nComponents * nBytes; + + /* + Nxyz = JPEG 2000 numerically lossless, where + "xyz" indicates the expected achieved bit rate (in + bits per pixel per band) for the final layer of each tile. + The decimal point is implicit and assumed to be one + digit from the right (i.e. xy.z). + */ + comrat = (1.0f * compressedSize * nBits) / rawSize; + comratInt = (nitf_Uint32)(comrat * 10.0f + 0.5f); + + /* write the comrat field */ + NITF_SNPRINTF(implControl->comratField->raw, + implControl->comratField->length + 1, + "N%03d", comratInt); + + return NITF_SUCCESS; +} + +NITFPRIV(void) implDestroy(nitf_CompressionControl ** control) +{ + if (control && *control) + { + ImplControl *implControl = (ImplControl*)*control; + if (implControl->container) + { + j2k_Container_destruct(&implControl->container); + } + if (implControl->writer) + { + j2k_Writer_destruct(&implControl->writer); + } + NITF_FREE(*control); + *control = NULL; + } +} + +#endif diff --git a/modules/c/j2k/shared/J2KDecompress.c b/modules/c/j2k/shared/J2KDecompress.c new file mode 100644 index 000000000..20fa2fca1 --- /dev/null +++ b/modules/c/j2k/shared/J2KDecompress.c @@ -0,0 +1,261 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifdef HAVE_J2K_H + +#include +#include + +NITF_CXX_GUARD + +NITFPRIV(nitf_DecompressionControl*) implOpen(nitf_ImageSubheader * subheader, + nrt_HashTable * options, + nitf_Error * error); +NITFPRIV(NITF_BOOL) implStart(nitf_DecompressionControl* control, + nitf_IOInterface* io, + nitf_Uint64 offset, + nitf_Uint64 fileLength, + nitf_BlockingInfo* blockInfo, + nitf_Uint64* blockMask, + nitf_Error* error); +NITFPRIV(nitf_Uint8*) implReadBlock(nitf_DecompressionControl *control, + nitf_Uint32 blockNumber, + nitf_Uint64* blockSize, + nitf_Error* error); +NITFPRIV(int) implFreeBlock(nitf_DecompressionControl* control, + nitf_Uint8* block, + nitf_Error* error); + +NITFPRIV(void) implClose(nitf_DecompressionControl** control); + +NITFPRIV(void) implMemFree(void* p); + +static const char *ident[] = +{ + NITF_PLUGIN_DECOMPRESSION_KEY, "C8", NULL +}; + +static nitf_DecompressionInterface interfaceTable = +{ + implOpen, implStart, implReadBlock, implFreeBlock, implClose, NULL +}; + +typedef struct _ImplControl +{ + nitf_BlockingInfo blockInfo; /* Kept for convenience */ + j2k_Reader *reader; /* j2k Reader */ + nitf_Uint64 offset; /* File offset to data */ + nitf_Uint64 fileLength; /* Length of compressed data in file */ +} +ImplControl; + +NITF_CXX_ENDGUARD + + +NITFAPI(char**) J2KDecompress_init(nitf_Error *error) +{ + return ident; +} + +NITFAPI(void) C8_cleanup(void) +{ + /* TODO */ +} + + +NITFPRIV(int) implFreeBlock(nitf_DecompressionControl* control, + nitf_Uint8* block, + nitf_Error* error) +{ + if (block) + implMemFree((void*)block); + return 1; +} + +NITFAPI(void*) C8_construct(char *compressionType, + nitf_Error* error) +{ + if (strcmp(compressionType, "C8") != 0) + { + nitf_Error_init(error, + "Unsupported compression type", + NITF_CTXT, + NITF_ERR_DECOMPRESSION); + + return NULL; + } + return((void *) &interfaceTable); +} + +NITFPRIV(nitf_Uint8*) implReadBlock(nitf_DecompressionControl *control, + nitf_Uint32 blockNumber, + nitf_Uint64* blockSize, + nitf_Error* error) +{ + ImplControl *implControl = (ImplControl*)control; + nrt_Uint8 *buf = NULL; + nrt_Uint64 bufSize; + j2k_Container* container = NULL; + + if (j2k_Reader_canReadTiles(implControl->reader, error)) + { + /* use j2k_Reader_readTile */ + nitf_Uint32 tileX, tileY; + + tileY = blockNumber / implControl->blockInfo.numBlocksPerRow; + tileX = blockNumber % implControl->blockInfo.numBlocksPerRow; + + if (0 == (bufSize = j2k_Reader_readTile(implControl->reader, tileX, + tileY, &buf, error))) + { + implMemFree(buf); + return NULL; + } + } + else + { + /* use j2k_Reader_readRegion using the block info */ + nitf_Uint32 tileX, tileY, x0, x1, y0, y1, totalRows, totalCols; + + tileY = blockNumber / implControl->blockInfo.numBlocksPerRow; + tileX = blockNumber % implControl->blockInfo.numBlocksPerRow; + + x0 = tileX * implControl->blockInfo.numColsPerBlock; + x1 = x0 + implControl->blockInfo.numColsPerBlock; + y0 = tileY * implControl->blockInfo.numRowsPerBlock; + y1 = y0 + implControl->blockInfo.numRowsPerBlock; + + /* check for last tiles */ + container = j2k_Reader_getContainer(implControl->reader, error); + if (container == NULL) + { + return NULL; + } + totalRows = j2k_Container_getHeight(container, error); + totalCols = j2k_Container_getWidth(container, error); + + if (x1 > totalCols) + x1 = totalCols; + if (y1 > totalRows) + y1 = totalRows; + + if (0 == (bufSize = j2k_Reader_readRegion(implControl->reader, x0, y0, + x1, y1, &buf, error))) + { + implMemFree(buf); + return NULL; + } + } + *blockSize = bufSize; + return buf; +} + +NITFPRIV(void*) implMemAlloc(size_t size, nitf_Error* error) +{ + void * p = NITF_MALLOC(size); + if (!p) + { + nitf_Error_init(error, + NITF_STRERROR( NITF_ERRNO ), + NITF_CTXT, + NITF_ERR_MEMORY); + } + else + { + memset(p, 0, size); + } + return p; +} + +NITFPRIV(void) implMemFree(void* p) +{ + if (p) NITF_FREE(p); +} + +NITFPRIV(void) implClose(nitf_DecompressionControl** control) +{ + if (control && *control) + { + ImplControl *implControl = (ImplControl*)*control; + if (implControl->reader) + { + j2k_Reader_destruct(&implControl->reader); + } + implMemFree(implControl); + *control = NULL; + } +} + +NITFPRIV(nitf_DecompressionControl*) implOpen(nitf_ImageSubheader * subheader, + nrt_HashTable * options, + nitf_Error * error) +{ + ImplControl *implControl = NULL; + (void)subheader; + (void)options; + + if (!(implControl = (ImplControl*)implMemAlloc(sizeof(ImplControl), error))) + goto CATCH_ERROR; + + return((nitf_DecompressionControl*) implControl); + + CATCH_ERROR: + { + implMemFree(implControl); + return NULL; + } +} + +NITFPRIV(NITF_BOOL) implStart(nitf_DecompressionControl* control, + nitf_IOInterface* io, + nitf_Uint64 offset, + nitf_Uint64 fileLength, + nitf_BlockingInfo* blockInfo, + nitf_Uint64* blockMask, + nitf_Error* error) +{ + ImplControl *implControl = NULL; + + /* TODO: In order to support M8, I think we would update this */ + (void)blockMask; + + implControl = (ImplControl*)control; + + if (nitf_IOInterface_seek(io, offset, NITF_SEEK_SET, error) < 0) + goto CATCH_ERROR; + + if (!(implControl->reader = j2k_Reader_openIO(io, error))) + goto CATCH_ERROR; + + implControl->offset = offset; + implControl->fileLength = fileLength; + implControl->blockInfo = *blockInfo; + return NITF_SUCCESS; + + CATCH_ERROR: + { + implMemFree(implControl); + return NITF_FAILURE; + } +} + +#endif diff --git a/modules/c/j2k/shared/wscript b/modules/c/j2k/shared/wscript new file mode 100644 index 000000000..072a6fd82 --- /dev/null +++ b/modules/c/j2k/shared/wscript @@ -0,0 +1,36 @@ +import os, subprocess +from waflib import Options +from os.path import splitext, dirname, join + +MAINTAINER = 'adam.sylvester@gd-ais.com' +VERSION = '1.0' +LANG = 'c' +USE = 'nitf-c j2k-c' +PLUGIN = 'nitf' +REMOVEPLUGINPREFIX = True +DEFINES = 'NITF_MODULE_EXPORTS HAVE_J2K_H J2K_MODULE_EXPORTS' + +configure = options = distclean = lambda p: None + +def build(bld): + variant = bld.env['VARIANT'] or 'default' + env = bld.all_envs[variant] + + if 'HAVE_J2K' in env: + pluginList = [] + plugins = bld.path.ant_glob('*.c') + + for p in plugins: + filename = str(p) + + kw = globals() + pluginName = splitext(filename)[0] + kw['NAME'] = pluginName + kw['LIBNAME'] = pluginName + kw['SOURCE'] = filename + + bld.plugin(**kw) + pluginList.append(pluginName) + + bld(features='add_targets', target='j2k-plugins', + targets_to_add=pluginList) \ No newline at end of file diff --git a/modules/c/j2k/source/Component.c b/modules/c/j2k/source/Component.c new file mode 100644 index 000000000..e12886d45 --- /dev/null +++ b/modules/c/j2k/source/Component.c @@ -0,0 +1,84 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "j2k/Component.h" + +J2KAPI(nrt_Uint32) j2k_Component_getWidth(j2k_Component *component, + nrt_Error *error) +{ + return component->iface->getWidth(component->data, error); +} + +J2KAPI(nrt_Uint32) j2k_Component_getHeight(j2k_Component *component, + nrt_Error *error) +{ + return component->iface->getHeight(component->data, error); +} + +J2KAPI(nrt_Uint32) j2k_Component_getPrecision(j2k_Component *component, + nrt_Error *error) +{ + return component->iface->getPrecision(component->data, error); +} + +J2KAPI(NRT_BOOL) j2k_Component_isSigned(j2k_Component *component, + nrt_Error *error) +{ + return component->iface->isSigned(component->data, error); +} + +J2KAPI(nrt_Int32) j2k_Component_getOffsetX(j2k_Component *component, + nrt_Error *error) +{ + return component->iface->getOffsetX(component->data, error); +} + +J2KAPI(nrt_Int32) j2k_Component_getOffsetY(j2k_Component *component, + nrt_Error *error) +{ + return component->iface->getOffsetY(component->data, error); +} + +J2KAPI(nrt_Uint32) j2k_Component_getSeparationX(j2k_Component *component, + nrt_Error *error) +{ + return component->iface->getSeparationX(component->data, error); +} + +J2KAPI(nrt_Uint32) j2k_Component_getSeparationY(j2k_Component *component, + nrt_Error *error) +{ + return component->iface->getSeparationY(component->data, error); +} + +J2KAPI(void) +j2k_Component_destruct(j2k_Component **component) +{ + if (*component) + { + if ((*component)->iface && (*component)->data) + (*component)->iface->destruct((*component)->data); + J2K_FREE(*component); + *component = NULL; + } +} + diff --git a/modules/c/j2k/source/Container.c b/modules/c/j2k/source/Container.c new file mode 100644 index 000000000..b869d66c3 --- /dev/null +++ b/modules/c/j2k/source/Container.c @@ -0,0 +1,135 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "j2k/Container.h" + + +J2KAPI(nrt_Uint32) j2k_Container_getGridWidth(j2k_Container *container, + nrt_Error *error) +{ + return container->iface->getGridWidth(container->data, error); +} + +J2KAPI(nrt_Uint32) j2k_Container_getGridHeight(j2k_Container *container, + nrt_Error *error) +{ + return container->iface->getGridHeight(container->data, error); +} + +J2KAPI(nrt_Uint32) j2k_Container_getNumComponents(j2k_Container *container, + nrt_Error *error) +{ + return container->iface->getNumComponents(container->data, error); +} + +J2KAPI(j2k_Component*) j2k_Container_getComponent(j2k_Container *container, + nrt_Uint32 idx, + nrt_Error *error) +{ + return container->iface->getComponent(container->data, idx, error); +} + +J2KAPI(nrt_Uint32) j2k_Container_getWidth(j2k_Container *container, + nrt_Error *error) +{ + nrt_Uint32 nComponents, i, width, cWidth; + nComponents = j2k_Container_getNumComponents(container, error); + width = 0; + for(i = 0; i < nComponents; ++i) + { + j2k_Component *c = j2k_Container_getComponent(container, i, error); + cWidth = j2k_Component_getWidth(c, error); + if (cWidth > width) + width = cWidth; + } + return width; +} + +J2KAPI(nrt_Uint32) j2k_Container_getHeight(j2k_Container *container, + nrt_Error *error) +{ + nrt_Uint32 nComponents, i, height, cHeight; + nComponents = j2k_Container_getNumComponents(container, error); + height = 0; + for(i = 0; i < nComponents; ++i) + { + j2k_Component *c = j2k_Container_getComponent(container, i, error); + cHeight = j2k_Component_getHeight(c, error); + if (cHeight > height) + height = cHeight; + } + return height; +} + +J2KAPI(nrt_Uint32) j2k_Container_getPrecision(j2k_Container *container, + nrt_Error *error) +{ + nrt_Uint32 nComponents, i, precision, cPrecision; + nComponents = j2k_Container_getNumComponents(container, error); + precision = 0; + for(i = 0; i < nComponents; ++i) + { + j2k_Component *c = j2k_Container_getComponent(container, i, error); + cPrecision = j2k_Component_getPrecision(c, error); + if (cPrecision > precision) + precision = cPrecision; + } + return precision; +} + +J2KAPI(nrt_Uint32) j2k_Container_getTilesX(j2k_Container *container, nrt_Error *error) +{ + return container->iface->getTilesX(container->data, error); +} + +J2KAPI(nrt_Uint32) j2k_Container_getTilesY(j2k_Container *container, nrt_Error *error) +{ + return container->iface->getTilesY(container->data, error); +} + +J2KAPI(nrt_Uint32) j2k_Container_getTileWidth(j2k_Container *container, nrt_Error *error) +{ + return container->iface->getTileWidth(container->data, error); +} + +J2KAPI(nrt_Uint32) j2k_Container_getTileHeight(j2k_Container *container, nrt_Error *error) +{ + return container->iface->getTileHeight(container->data, error); +} + +J2KAPI(int) j2k_Container_getImageType(j2k_Container *container, nrt_Error *error) +{ + return container->iface->getImageType(container->data, error); +} + +J2KAPI(void) +j2k_Container_destruct(j2k_Container **container) +{ + if (*container) + { + if ((*container)->iface && (*container)->data) + (*container)->iface->destruct((*container)->data); + J2K_FREE(*container); + *container = NULL; + } +} + diff --git a/modules/c/j2k/source/JasPerImpl.c b/modules/c/j2k/source/JasPerImpl.c new file mode 100644 index 000000000..c500a59e5 --- /dev/null +++ b/modules/c/j2k/source/JasPerImpl.c @@ -0,0 +1,924 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifdef HAVE_JASPER_H + +#include "j2k/Container.h" +#include "j2k/Reader.h" +#include "j2k/Writer.h" + +#include + +/******************************************************************************/ +/* TYPES & DECLARATIONS */ +/******************************************************************************/ + +typedef struct _IOControl +{ + nrt_IOInterface *io; + nrt_Off offset; + nrt_Off length; + nrt_Off ioSize; + int isRead; + nrt_Error error; +}IOControl; + +typedef struct _JasPerReaderImpl +{ + nrt_Off ioOffset; + nrt_IOInterface *io; + int ownIO; + j2k_Container *container; +} JasPerReaderImpl; + +typedef struct _JasPerWriterImpl +{ + j2k_Container *container; + jas_image_t *image; +} JasPerWriterImpl; + +J2KPRIV(int) JasPerIO_read(jas_stream_obj_t *obj, char *buf, int cnt); +J2KPRIV(int) JasPerIO_write(jas_stream_obj_t *obj, char *buf, int cnt); +J2KPRIV(long) JasPerIO_seek(jas_stream_obj_t *obj, long offset, int origin); +J2KPRIV(int) JasPerIO_close(jas_stream_obj_t *obj); + +static jas_stream_ops_t IOInterface = {JasPerIO_read, JasPerIO_write, + JasPerIO_seek, JasPerIO_close}; + + +J2KPRIV( nrt_Uint64) JasPerReader_readTile(J2K_USER_DATA *, nrt_Uint32, + nrt_Uint32, nrt_Uint8 **, + nrt_Error *); +J2KPRIV( nrt_Uint64) JasPerReader_readRegion(J2K_USER_DATA *, nrt_Uint32, + nrt_Uint32, nrt_Uint32, + nrt_Uint32, nrt_Uint8 **, + nrt_Error *); +J2KPRIV( j2k_Container*) JasPerReader_getContainer(J2K_USER_DATA *, nrt_Error *); +J2KPRIV(void) JasPerReader_destruct(J2K_USER_DATA *); + +static j2k_IReader ReaderInterface = {NULL, &JasPerReader_readTile, + &JasPerReader_readRegion, + &JasPerReader_getContainer, + &JasPerReader_destruct }; + +J2KPRIV( NRT_BOOL) JasPerWriter_setTile(J2K_USER_DATA *, + nrt_Uint32, nrt_Uint32, + const nrt_Uint8 *, nrt_Uint32, + nrt_Error *); +J2KPRIV( NRT_BOOL) JasPerWriter_write(J2K_USER_DATA *, nrt_IOInterface *, + nrt_Error *); +J2KPRIV( j2k_Container*) JasPerWriter_getContainer(J2K_USER_DATA *, nrt_Error *); +J2KPRIV(void) JasPerWriter_destruct(J2K_USER_DATA *); + +static j2k_IWriter WriterInterface = {&JasPerWriter_setTile, + &JasPerWriter_write, + &JasPerWriter_getContainer, + &JasPerWriter_destruct }; + + +J2KPRIV( J2K_BOOL) JasPer_setup(JasPerReaderImpl *, jas_stream_t **, + jas_image_t **, nrt_Error *); +J2KPRIV(void) JasPer_cleanup(jas_stream_t **, jas_image_t **); +J2KPRIV( J2K_BOOL) JasPer_readHeader(JasPerReaderImpl *, nrt_Error *); +J2KPRIV( J2K_BOOL) JasPer_initImage(JasPerWriterImpl *, j2k_WriterOptions *, + nrt_Error *); + +/******************************************************************************/ +/* IO */ +/******************************************************************************/ + +J2KPRIV(jas_stream_t*) JasPer_createIO(nrt_IOInterface *io, + int openMode, + nrt_Error *error) +{ + jas_stream_t *stream = NULL; + IOControl *ctrl = NULL; + + if (!(stream = (jas_stream_t*)J2K_MALLOC(sizeof(jas_stream_t)))) + { + nrt_Error_init(error, + "Error creating stream object", + NRT_CTXT, + NRT_ERR_MEMORY); + return NULL; + } + memset(stream, 0, sizeof(jas_stream_t)); + + if (!(ctrl = (IOControl *) J2K_MALLOC(sizeof(IOControl)))) + { + nrt_Error_init(error, "Error creating control object", NRT_CTXT, + NRT_ERR_MEMORY); + return NULL; + } + ctrl->io = io; + ctrl->offset = nrt_IOInterface_tell(io, error); + ctrl->ioSize = nrt_IOInterface_getSize(io, error); + ctrl->length = ctrl->ioSize - ctrl->offset; + + stream->openmode_ = openMode; + stream->flags_ = 0; + stream->rwcnt_ = 0; + stream->rwlimit_ = -1; + stream->obj_ = (void *) ctrl; + stream->ops_ = &IOInterface; + + if ((stream->bufbase_ = J2K_MALLOC(JAS_STREAM_BUFSIZE + + JAS_STREAM_MAXPUTBACK))) + { + stream->bufmode_ |= JAS_STREAM_FREEBUF; + stream->bufsize_ = JAS_STREAM_BUFSIZE; + } + else + { + /* The buffer allocation has failed. Resort to unbuffered ops. */ + stream->bufbase_ = stream->tinybuf_; + stream->bufsize_ = 1; + } + stream->bufstart_ = &stream->bufbase_[JAS_STREAM_MAXPUTBACK]; + stream->ptr_ = stream->bufstart_; + stream->cnt_ = 0; + stream->bufmode_ |= JAS_STREAM_FULLBUF & JAS_STREAM_BUFMODEMASK; + + return stream; +} + +J2KPRIV(int) JasPerIO_read(jas_stream_obj_t *obj, char *buf, int cnt) +{ + IOControl *ctrl = (IOControl*)obj; + nrt_Off remaining; + + /* JasPer can request more bytes than we have, so we need to compute */ + remaining = ctrl->ioSize - nrt_IOInterface_tell(ctrl->io, &ctrl->error); + if (remaining < (nrt_Off)cnt) + cnt = (int)remaining; + + if (!nrt_IOInterface_read(ctrl->io, buf, (size_t)cnt, &ctrl->error)) + { + return -1; + } + return cnt; +} + +J2KPRIV(int) JasPerIO_write(jas_stream_obj_t *obj, char *buf, int cnt) +{ + nrt_Error error; + IOControl *ctrl = (IOControl*)obj; + + if (!nrt_IOInterface_write(ctrl->io, buf, (size_t)cnt, &ctrl->error)) + { + return -1; + } + return cnt; +} + +J2KPRIV(long) JasPerIO_seek(jas_stream_obj_t *obj, long offset, int origin) +{ + nrt_Off off; + int whence = NRT_SEEK_SET; + IOControl *ctrl = (IOControl*)obj; + + if (origin == SEEK_SET) + { + offset = offset + ctrl->offset; + } + else if (origin == SEEK_END) + { + offset = offset + ctrl->offset + ctrl->length; + } + else if (origin == SEEK_CUR) + { + whence = NRT_SEEK_CUR; + } + + if (!(off = nrt_IOInterface_seek(ctrl->io, offset, whence, &ctrl->error))) + { + return -1; + } + return (long)off; +} + +J2KPRIV(int) JasPerIO_close(jas_stream_obj_t *obj) +{ + /* TODO - I don't think we should close it.. */ + return 0; +} + + +/******************************************************************************/ +/* UTILITIES */ +/******************************************************************************/ + +J2KPRIV( J2K_BOOL) +JasPer_setup(JasPerReaderImpl *impl, jas_stream_t **stream, + jas_image_t **image, nrt_Error *error) +{ + int fmtid; + char *fmtname = NULL; + jas_image_fmtinfo_t *fmtinfo; + + if (nrt_IOInterface_seek(impl->io, impl->ioOffset, NRT_SEEK_SET, error) < 0) + { + goto CATCH_ERROR; + } + + if (!(*stream = JasPer_createIO(impl->io, JAS_STREAM_READ, error))) + { + goto CATCH_ERROR; + } + + if ((fmtid = jas_image_getfmt(*stream)) < 0) + { + nrt_Error_init(error, "Error in JasPer: reading format ID", NRT_CTXT, + NRT_ERR_UNK); + goto CATCH_ERROR; + } + + if (!(fmtname = jas_image_fmttostr(fmtid))) + { + nrt_Error_init(error, "Error in JasPer: invalid format ID", NRT_CTXT, + NRT_ERR_UNK); + goto CATCH_ERROR; + } + fmtinfo = jas_image_lookupfmtbyid(fmtid); + + if (!(*image = jas_image_decode(*stream, fmtid, NULL))) + { + nrt_Error_initf(error, NRT_CTXT, NRT_ERR_UNK, + "Error in JasPer: decoding image in format %s", + NRT_CTXT, fmtname); + goto CATCH_ERROR; + } + + return J2K_SUCCESS; + + CATCH_ERROR: + { + JasPer_cleanup(stream, image); + return J2K_FAILURE; + } +} + +J2KPRIV(void) +JasPer_cleanup(jas_stream_t **stream, jas_image_t **image) +{ + if (stream && *stream) + { + jas_stream_close(*stream); + *stream = NULL; + } + if (image && *image) + { + jas_image_destroy(*image); + *image = NULL; + } +} + +J2KPRIV( NRT_BOOL) +JasPer_readHeader(JasPerReaderImpl *impl, nrt_Error *error) +{ + jas_stream_t *stream = NULL; + jas_image_t *image = NULL; + NRT_BOOL rc = NRT_SUCCESS; + jas_clrspc_t colorSpace; + + if (!JasPer_setup(impl, &stream, &image, error)) + { + goto CATCH_ERROR; + } + + if (!impl->container) + { + /* initialize the container */ + nrt_Uint32 idx, nComponents, width, height; + j2k_Component **components = NULL; + int imageType; + + nComponents = jas_image_numcmpts(image); + + if (!(components = (j2k_Component**)J2K_MALLOC( + sizeof(j2k_Component*) * nComponents))) + { + nrt_Error_init(error, NRT_STRERROR(NRT_ERRNO), NRT_CTXT, + NRT_ERR_MEMORY); + goto CATCH_ERROR; + } + + for(idx = 0; idx < nComponents; ++idx) + { + jas_image_cmpt_t *c = image->cmpts_[idx]; + if (!(components[idx] = j2k_Component_construct(c->width_, + c->height_, + c->prec_, + c->sgnd_, + c->tlx_, + c->tly_, + c->hstep_, + c->vstep_, + error))) + { + goto CATCH_ERROR; + } + } + + colorSpace = jas_image_clrspc(image); + if (jas_clrspc_fam(colorSpace) == JAS_CLRSPC_FAM_RGB) + imageType = J2K_TYPE_RGB; + else if (jas_clrspc_fam(colorSpace) == JAS_CLRSPC_FAM_GRAY) + imageType = J2K_TYPE_MONO; + else + imageType = J2K_TYPE_UNKNOWN; + + width = jas_image_width(image); + height = jas_image_height(image); + + /* JasPer hides tile information inside the jpc decoder, so we do not + * have access to it here. + * + * For now, we will fake the tile information by representing raw J2K as + * having 1x1 tiles. + */ + if (!(impl->container = j2k_Container_construct(width, height, + nComponents, + components, + width, height, + imageType, error))) + { + goto CATCH_ERROR; + } + } + + goto CLEANUP; + + CATCH_ERROR: + { + rc = NRT_FAILURE; + } + + CLEANUP: + { + JasPer_cleanup(&stream, &image); + } + return rc; +} + +J2KPRIV( NRT_BOOL) +JasPer_initImage(JasPerWriterImpl *impl, j2k_WriterOptions *writerOps, + nrt_Error *error) +{ + NRT_BOOL rc = NRT_SUCCESS; + jas_clrspc_t colorSpace; + jas_image_cmptparm_t *cmptParams = NULL; + j2k_Component *component = NULL; + nrt_Uint32 i, nComponents, height, width, nBits; + int imageType; + J2K_BOOL isSigned; + + nComponents = j2k_Container_getNumComponents(impl->container, error); + width = j2k_Container_getWidth(impl->container, error); + height = j2k_Container_getHeight(impl->container, error); + nBits = j2k_Container_getPrecision(impl->container, error); + imageType = j2k_Container_getImageType(impl->container, error); + + if (!(cmptParams = (jas_image_cmptparm_t*)J2K_MALLOC(sizeof( + jas_image_cmptparm_t) * nComponents))) + { + nrt_Error_init(error, NRT_STRERROR(NRT_ERRNO), NRT_CTXT, + NRT_ERR_MEMORY); + goto CATCH_ERROR; + } + + for(i = 0; i < nComponents; ++i) + { + component = j2k_Container_getComponent(impl->container, i, error); + cmptParams[i].width = j2k_Component_getWidth(component, error); + cmptParams[i].height = j2k_Component_getHeight(component, error); + cmptParams[i].prec = j2k_Component_getPrecision(component, error); + cmptParams[i].tlx = j2k_Component_getOffsetX(component, error); + cmptParams[i].tly = j2k_Component_getOffsetY(component, error); + cmptParams[i].hstep = j2k_Component_getSeparationX(component, error); + cmptParams[i].vstep = j2k_Component_getSeparationY(component, error); + cmptParams[i].sgnd = j2k_Component_isSigned(component, error); + } + + if (!(impl->image = jas_image_create(nComponents, cmptParams, + JAS_CLRSPC_UNKNOWN))) + { + + nrt_Error_init(error, "Error creating JasPer image", NRT_CTXT, + NRT_ERR_INVALID_OBJECT); + goto CATCH_ERROR; + } + + if (imageType == J2K_TYPE_RGB && nComponents == 3) + { + jas_image_setclrspc(impl->image, JAS_CLRSPC_GENRGB); + jas_image_setcmpttype(impl->image, 0, + JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_RGB_R)); + jas_image_setcmpttype(impl->image, 1, + JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_RGB_G)); + jas_image_setcmpttype(impl->image, 2, + JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_RGB_B)); + } + else + { + jas_image_setclrspc(impl->image, JAS_CLRSPC_GENGRAY); + for(i = 0; i < nComponents; ++i) + { + jas_image_setcmpttype(impl->image, i, + JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_GRAY_Y)); + } + } + + goto CLEANUP; + + CATCH_ERROR: + { + rc = NRT_FAILURE; + } + + CLEANUP: + { + if (cmptParams) + J2K_FREE(cmptParams); + } + + + return rc; +} + +/******************************************************************************/ +/* READER */ +/******************************************************************************/ + +#define PRIV_READ_MATRIX(_SZ, _X0, _Y0, _X1, _Y1) { \ +nrt_Uint32 rowIdx, colIdx, rowCt, colCt; \ +nrt_Uint##_SZ* data##_SZ = (nrt_Uint##_SZ*)bufPtr; \ +jas_matrix_t* matrix##_SZ = NULL; \ +rowCt = _Y1 - _Y0; colCt = _X1 - _X0; \ +matrix##_SZ = jas_matrix_create(rowCt, colCt); \ +if (!matrix##_SZ){ \ + nrt_Error_init(error, "Cannot allocate memory - JasPer jas_matrix_create failed!", \ + NRT_CTXT, NRT_ERR_MEMORY); \ + return 0; \ +} \ +jas_image_readcmpt (image, cmptIdx, _X0, _Y0, colCt, rowCt, matrix##_SZ); \ +for (rowIdx = 0; rowIdx < rowCt; ++rowIdx){ \ + for (colIdx = 0; colIdx < colCt; ++colIdx){ \ + *data##_SZ++ = (nrt_Uint##_SZ)jas_matrix_get(matrix##_SZ, rowIdx, colIdx); \ + } \ +} \ +jas_matrix_destroy (matrix##_SZ); } + + +J2KPRIV( nrt_Uint64) +JasPerReader_readRegion(J2K_USER_DATA *data, nrt_Uint32 x0, nrt_Uint32 y0, + nrt_Uint32 x1, nrt_Uint32 y1, nrt_Uint8 **buf, + nrt_Error *error) +{ + JasPerReaderImpl *impl = (JasPerReaderImpl*) data; + jas_stream_t *stream = NULL; + jas_image_t *image = NULL; + nrt_Uint32 i, cmptIdx, nBytes, nComponents; + nrt_Uint64 bufSize, componentSize; + nrt_Uint8 *bufPtr = NULL; + + if (!JasPer_setup(impl, &stream, &image, error)) + { + goto CATCH_ERROR; + } + + if (x1 == 0) + x1 = j2k_Container_getWidth(impl->container, error); + if (y1 == 0) + y1 = j2k_Container_getHeight(impl->container, error); + + nBytes = (j2k_Container_getPrecision(impl->container, error) - 1) / 8 + 1; + componentSize = (nrt_Uint64)(x1 - x0) * (y1 - y0) * nBytes; + nComponents = j2k_Container_getNumComponents(impl->container, error); + bufSize = componentSize * nComponents; + + if (buf && !*buf) + { + *buf = (nrt_Uint8*)J2K_MALLOC(bufSize); + if (!*buf) + { + nrt_Error_init(error, NRT_STRERROR(NRT_ERRNO), NRT_CTXT, + NRT_ERR_MEMORY); + goto CATCH_ERROR; + } + } + + bufPtr = *buf; + for (cmptIdx = 0; cmptIdx < nComponents; ++cmptIdx) + { + nrt_Uint32 nRows, nCols; + nRows = jas_image_cmptheight(image, cmptIdx) * + jas_image_cmptvstep(image, cmptIdx); + nCols = jas_image_cmptwidth(image, cmptIdx) * + jas_image_cmpthstep(image, cmptIdx); + if (x1 > nCols || x0 >= x1 || y1 > nRows || y0 >= y1) + { + nrt_Error_init(error, "Invalid region requested", NRT_CTXT, + NRT_ERR_INVALID_OBJECT); + goto CATCH_ERROR; + } + + switch(nBytes) + { + case 1: + { + PRIV_READ_MATRIX(8, x0, y0, x1, y1); + break; + } + case 2: + { + PRIV_READ_MATRIX(16, x0, y0, x1, y1); + break; + } + case 4: + { + PRIV_READ_MATRIX(32, x0, y0, x1, y1); + break; + } + default: + nrt_Error_init(error, "Unknown pixel size", NRT_CTXT, + NRT_ERR_INVALID_OBJECT); + goto CATCH_ERROR; + } + bufPtr += componentSize; + } + + goto CLEANUP; + + CATCH_ERROR: + { + bufSize = 0; + } + + CLEANUP: + { + JasPer_cleanup(&stream, &image); + } + return bufSize; +} + +J2KPRIV( nrt_Uint64) +JasPerReader_readTile(J2K_USER_DATA *data, nrt_Uint32 tileX, nrt_Uint32 tileY, + nrt_Uint8 **buf, nrt_Error *error) +{ + JasPerReaderImpl *impl = (JasPerReaderImpl*) data; + nrt_Uint32 width, height; + + width = j2k_Container_getWidth(impl->container, error); + height = j2k_Container_getHeight(impl->container, error); + + /* TODO - for now, we are treating the image as 1x1 */ + /* might want to return an error instead */ + return JasPerReader_readRegion(data, 0, 0, width, height, buf, error); +} + +J2KPRIV( j2k_Container*) +JasPerReader_getContainer(J2K_USER_DATA *data, nrt_Error *error) +{ + JasPerReaderImpl *impl = (JasPerReaderImpl*) data; + return impl->container; +} + + +J2KPRIV(void) +JasPerReader_destruct(J2K_USER_DATA * data) +{ + if (data) + { + JasPerReaderImpl *impl = (JasPerReaderImpl*) data; + if (impl->ownIO && impl->io) + { + nrt_IOInterface_destruct(&impl->io); + impl->io = NULL; + } + if (impl->container) + { + j2k_Container_destruct(&impl->container); + } + J2K_FREE(data); + } +} + + +/******************************************************************************/ +/* WRITER */ +/******************************************************************************/ + +#define PRIV_WRITE_MATRIX(_SZ) { \ +nrt_Uint32 rowIdx, colIdx, cmpIdx; \ +nrt_Uint##_SZ* data##_SZ = (nrt_Uint##_SZ*)buf; \ +jas_matrix_t* matrix##_SZ = jas_matrix_create(tileHeight, tileWidth); \ +if (!matrix##_SZ){ \ + nrt_Error_init(error, "Cannot allocate memory - JasPer jas_matrix_create failed!", \ + NRT_CTXT, NRT_ERR_MEMORY); \ + goto CATCH_ERROR; \ +} \ +for (cmpIdx = 0; cmpIdx < nComponents; ++cmpIdx){ \ + for (rowIdx = 0; rowIdx < tileHeight; ++rowIdx){ \ + for (colIdx = 0; colIdx < tileWidth; ++colIdx){ \ + jas_matrix_set(matrix##_SZ, rowIdx, colIdx, (jas_seqent_t)*data##_SZ++); \ + } \ + } \ + if (jas_image_writecmpt (impl->image, cmpIdx, tileX * tileWidth, \ + tileY * tileHeight, tileWidth, tileHeight, \ + matrix##_SZ) != 0) { \ + nrt_Error_init(error, "JasPer was unable to write image component", \ + NRT_CTXT, NRT_ERR_UNK); \ + jas_matrix_destroy (matrix##_SZ); \ + goto CATCH_ERROR; \ + } \ +} \ +jas_matrix_destroy (matrix##_SZ); } + + +J2KPRIV( NRT_BOOL) +JasPerWriter_setTile(J2K_USER_DATA *data, nrt_Uint32 tileX, nrt_Uint32 tileY, + const nrt_Uint8 *buf, nrt_Uint32 tileSize, + nrt_Error *error) +{ + JasPerWriterImpl *impl = (JasPerWriterImpl*) data; + NRT_BOOL rc = NRT_SUCCESS; + nrt_Uint32 i, nComponents, tileHeight, tileWidth, nBits, nBytes; + + nComponents = j2k_Container_getNumComponents(impl->container, error); + tileWidth = j2k_Container_getTileWidth(impl->container, error); + tileHeight = j2k_Container_getTileHeight(impl->container, error); + nBits = j2k_Container_getPrecision(impl->container, error); + nBytes = (nBits - 1) / 8 + 1; + + switch(nBytes) + { + case 1: + PRIV_WRITE_MATRIX(8); + break; + case 2: + PRIV_WRITE_MATRIX(16); + break; + case 4: + PRIV_WRITE_MATRIX(32); + break; + default: + nrt_Error_init(error, "Invalid pixel size", NRT_CTXT, + NRT_ERR_INVALID_OBJECT); + goto CATCH_ERROR; + } + + goto CLEANUP; + + CATCH_ERROR: + { + rc = NRT_FAILURE; + } + + CLEANUP: + { + } + + return rc; +} + +J2KPRIV( NRT_BOOL) +JasPerWriter_write(J2K_USER_DATA *data, nrt_IOInterface *io, nrt_Error *error) +{ + JasPerWriterImpl *impl = (JasPerWriterImpl*) data; + jas_stream_t *stream = NULL; + NRT_BOOL rc = NRT_SUCCESS; + + if (!(stream = JasPer_createIO(io, JAS_STREAM_WRITE| JAS_STREAM_BINARY, + error))) + { + goto CATCH_ERROR; + } + + if (jas_image_encode(impl->image, stream, + jas_image_strtofmt((char*)"jpc"), NULL) != 0) + { + nrt_Error_init(error, "Error encoding image", NRT_CTXT, + NRT_ERR_INVALID_OBJECT); + goto CATCH_ERROR; + } + jas_stream_flush(stream); + + if (jas_stream_close(stream) != 0) + { + nrt_Error_init(error, "Error closing stream", NRT_CTXT, + NRT_ERR_INVALID_OBJECT); + goto CATCH_ERROR; + } + + goto CLEANUP; + + CATCH_ERROR: + { + rc = NRT_FAILURE; + } + + CLEANUP: + { + } + + return rc; +} + +J2KPRIV( j2k_Container*) +JasPerWriter_getContainer(J2K_USER_DATA *data, nrt_Error *error) +{ + JasPerWriterImpl *impl = (JasPerWriterImpl*) data; + return impl->container; +} + +J2KPRIV(void) +JasPerWriter_destruct(J2K_USER_DATA * data) +{ + if (data) + { + JasPerWriterImpl *impl = (JasPerWriterImpl*) data; + + /* should we clear the formats? */ + /*jas_image_clearfmts();*/ + if (impl->image) + { + jas_image_destroy(impl->image); + } + /* we'll leave the container alone, unless we decide to clone it */ + J2K_FREE(data); + } +} + +/******************************************************************************/ +/******************************************************************************/ +/* PUBLIC FUNCTIONS */ +/******************************************************************************/ +/******************************************************************************/ + +J2KAPI(j2k_Reader*) j2k_Reader_open(const char *fname, nrt_Error *error) +{ + j2k_Reader *reader = NULL; + nrt_IOInterface *io = NULL; + + if (!fname) + { + nrt_Error_init(error, "NULL filename", NRT_CTXT, + NRT_ERR_INVALID_OBJECT); + goto CATCH_ERROR; + } + + if (!(io = nrt_IOHandleAdapter_open(fname, NRT_ACCESS_READONLY, + NRT_OPEN_EXISTING, error))) + goto CATCH_ERROR; + + if (!(reader = j2k_Reader_openIO(io, error))) + goto CATCH_ERROR; + + ((JasPerReaderImpl*) reader->data)->ownIO = 1; + + return reader; + + CATCH_ERROR: + { + if (io) + nrt_IOInterface_destruct(&io); + if (reader) + j2k_Reader_destruct(&reader); + return NULL; + } +} + + +J2KAPI(j2k_Reader*) j2k_Reader_openIO(nrt_IOInterface *io, nrt_Error *error) +{ + JasPerReaderImpl *impl = NULL; + j2k_Reader *reader = NULL; + + /* Initialize jasper - TODO is this ok to do more than once? */ + if (jas_init()) + { + nrt_Error_init(error, "Error initializing JasPer library", + NRT_CTXT, NRT_ERR_MEMORY); + goto CATCH_ERROR; + } + + /* create the Reader interface */ + impl = (JasPerReaderImpl *) J2K_MALLOC(sizeof(JasPerReaderImpl)); + if (!impl) + { + nrt_Error_init(error, NRT_STRERROR(NRT_ERRNO), NRT_CTXT, NRT_ERR_MEMORY); + goto CATCH_ERROR; + } + memset(impl, 0, sizeof(JasPerReaderImpl)); + + reader = (j2k_Reader*) J2K_MALLOC(sizeof(j2k_Reader)); + if (!reader) + { + nrt_Error_init(error, NRT_STRERROR(NRT_ERRNO), NRT_CTXT, NRT_ERR_MEMORY); + goto CATCH_ERROR; + } + memset(reader, 0, sizeof(j2k_Reader)); + reader->data = impl; + reader->iface = &ReaderInterface; + + /* initialize the interfaces */ + impl->io = io; + impl->ioOffset = nrt_IOInterface_tell(io, error); + + if (!JasPer_readHeader(impl, error)) + { + goto CATCH_ERROR; + } + + /* done */ + return reader; + + CATCH_ERROR: + { + if (reader) + { + j2k_Reader_destruct(&reader); + } + else if (impl) + { + JasPerReader_destruct((J2K_USER_DATA*) impl); + } + return NULL; + } +} + + +J2KAPI(j2k_Writer*) j2k_Writer_construct(j2k_Container *container, + j2k_WriterOptions *options, + nrt_Error *error) +{ + j2k_Writer *writer = NULL; + JasPerWriterImpl *impl = NULL; + + /* Initialize jasper - TODO is this ok to do more than once? */ + if (jas_init()) + { + nrt_Error_init(error, "Error initializing JasPer library", + NRT_CTXT, NRT_ERR_MEMORY); + goto CATCH_ERROR; + } + + writer = (j2k_Writer*) J2K_MALLOC(sizeof(j2k_Container)); + if (!writer) + { + nrt_Error_init(error, NRT_STRERROR(NRT_ERRNO), NRT_CTXT, NRT_ERR_MEMORY); + goto CATCH_ERROR; + } + memset(writer, 0, sizeof(j2k_Writer)); + + /* create the Writer interface */ + impl = (JasPerWriterImpl *) J2K_MALLOC(sizeof(JasPerWriterImpl)); + if (!impl) + { + nrt_Error_init(error, NRT_STRERROR(NRT_ERRNO), NRT_CTXT, NRT_ERR_MEMORY); + goto CATCH_ERROR; + } + memset(impl, 0, sizeof(JasPerWriterImpl)); + impl->container = container; + + if (!(JasPer_initImage(impl, options, error))) + { + goto CATCH_ERROR; + } + + writer->data = impl; + writer->iface = &WriterInterface; + + return writer; + + CATCH_ERROR: + { + if (writer) + { + j2k_Writer_destruct(&writer); + } + return NULL; + } +} + +#endif diff --git a/modules/c/j2k/source/KakaduImpl.cpp b/modules/c/j2k/source/KakaduImpl.cpp new file mode 100644 index 000000000..a85b90a11 --- /dev/null +++ b/modules/c/j2k/source/KakaduImpl.cpp @@ -0,0 +1,886 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifdef HAVE_KAKADU_H + +#include "j2k/Container.h" +#include "j2k/Reader.h" +#include "j2k/Writer.h" + +#include +#include +#include +#include +#include +#include + + +/******************************************************************************/ +/* TYPES & DECLARATIONS */ +/******************************************************************************/ + +J2KPRIV( nrt_Uint32) KakaduContainer_getTilesX(J2K_USER_DATA *, nrt_Error *); +J2KPRIV( nrt_Uint32) KakaduContainer_getTilesY(J2K_USER_DATA *, nrt_Error *); +J2KPRIV( nrt_Uint32) KakaduContainer_getTileWidth(J2K_USER_DATA *, nrt_Error *); +J2KPRIV( nrt_Uint32) KakaduContainer_getTileHeight(J2K_USER_DATA *, nrt_Error *); +J2KPRIV( nrt_Uint32) KakaduContainer_getWidth(J2K_USER_DATA *, nrt_Error *); +J2KPRIV( nrt_Uint32) KakaduContainer_getHeight(J2K_USER_DATA *, nrt_Error *); +J2KPRIV( nrt_Uint32) KakaduContainer_getNumComponents(J2K_USER_DATA *, nrt_Error *); +J2KPRIV( nrt_Uint32) KakaduContainer_getComponentBytes(J2K_USER_DATA *, nrt_Error *); +J2KPRIV( nrt_Uint32) KakaduContainer_getComponentBits(J2K_USER_DATA *, nrt_Error *); +J2KPRIV( int) KakaduContainer_getImageType(J2K_USER_DATA *, nrt_Error *); +J2KPRIV( J2K_BOOL) KakaduContainer_isSigned(J2K_USER_DATA *, nrt_Error *); +J2KPRIV(void) KakaduContainer_destruct(J2K_USER_DATA *); + +static j2k_IContainer ContainerInterface = { &KakaduContainer_getTilesX, + &KakaduContainer_getTilesY, + &KakaduContainer_getTileWidth, + &KakaduContainer_getTileHeight, + &KakaduContainer_getWidth, + &KakaduContainer_getHeight, + &KakaduContainer_getNumComponents, + &KakaduContainer_getComponentBytes, + &KakaduContainer_getComponentBits, + &KakaduContainer_getImageType, + &KakaduContainer_isSigned, + &KakaduContainer_destruct}; + +J2KPRIV( NRT_BOOL ) KakaduReader_canReadTiles(J2K_USER_DATA *, nrt_Error *); +J2KPRIV( nrt_Uint64) KakaduReader_readTile(J2K_USER_DATA *, nrt_Uint32, + nrt_Uint32, nrt_Uint8 **, + nrt_Error *); +J2KPRIV( nrt_Uint64) KakaduReader_readRegion(J2K_USER_DATA *, nrt_Uint32, + nrt_Uint32, nrt_Uint32, + nrt_Uint32, nrt_Uint8 **, + nrt_Error *); +J2KPRIV( j2k_Container*) KakaduReader_getContainer(J2K_USER_DATA *, nrt_Error *); +J2KPRIV(void) KakaduReader_destruct(J2K_USER_DATA *); + +static j2k_IReader ReaderInterface = {&KakaduReader_canReadTiles, + &KakaduReader_readTile, + &KakaduReader_readRegion, + &KakaduReader_getContainer, + &KakaduReader_destruct }; + +J2KPRIV( NRT_BOOL) KakaduWriter_setTile(J2K_USER_DATA *, + nrt_Uint32, nrt_Uint32, + nrt_Uint8 *, nrt_Uint32, + nrt_Error *); +J2KPRIV( NRT_BOOL) KakaduWriter_write(J2K_USER_DATA *, nrt_IOInterface *, + nrt_Error *); +J2KPRIV( j2k_Container*) KakaduWriter_getContainer(J2K_USER_DATA *, nrt_Error *); +J2KPRIV(void) KakaduWriter_destruct(J2K_USER_DATA *); + +static j2k_IWriter WriterInterface = {&KakaduWriter_setTile, + &KakaduWriter_write, + &KakaduWriter_getContainer, + &KakaduWriter_destruct }; + +/******************************************************************************/ +/* IMPLEMENTATION CLASSES */ +/******************************************************************************/ + +namespace j2k +{ +namespace kakadu +{ + +class IOStream : public kdu_compressed_source +{ +public: + IOStream(nrt_IOInterface *io, bool own = false) : + mIO(io), mOwn(own), mCapabilities(KDU_SOURCE_CAP_SEQUENTIAL + | KDU_SOURCE_CAP_SEEKABLE) + { + mOffset = nrt_IOInterface_tell(mIO, &mError); + } + + ~IOStream() + { + close(); + if (mOwn) + { + nrt_IOInterface_destruct(&mIO); + } + } + + virtual int get_capabilities() + { + return mCapabilities; + } + + virtual bool seek(kdu_long offset) + { + if (!nrt_IOInterface_seek(mIO, mOffset + offset, NRT_SEEK_SET, &mError)) + return false; + return true; + } + + virtual kdu_long get_pos() + { + nrt_Off tell = nrt_IOInterface_tell(mIO, &mError); + if (tell >= 0) + return tell - mOffset; + return -1; + } + + virtual int read(kdu_byte *buf, int num_bytes) + { + if (!nrt_IOInterface_read(mIO, (char*)buf, num_bytes, &mError)) + return 0; + return num_bytes; + } + + virtual bool close() + { + if (mOwn) + nrt_IOInterface_close(mIO, &mError); + return true; + } + + void ownIO() + { + mOwn = true; + } + +private: + nrt_IOInterface *mIO; + bool mOwn; + int mCapabilities; + nrt_Off mOffset; + nrt_Error mError; +}; + + +class ErrorHandler : public kdu_message +{ +public: + void put_text(const char *s) + { + mStream << s; + throw std::string(s); + } + + void put_text(const kdu_uint16 *s) + { + mStream << s; + } + + void flush(bool endOfMessage = false) + { + if (endOfMessage) + throw std::string(mStream.str()); + } + +protected: + std::stringstream mStream; +}; + + + +void copyLine(nrt_Uint8 *dest, kdu_line_buf &src, int bitsPerSample, + int outputBytes) +{ + int samples = src.get_width(); + + if (src.get_buf32()) + { + throw std::string("Not implemented"); + } + else if (src.get_buf16()) + { + kdu_sample16 *sp = src.get_buf16(); + kdu_int16 val; + kdu_int16 bitShift = 0; + + switch(outputBytes) + { + case 1: + { + bitShift = bitsPerSample < 8 ? 8 - bitsPerSample : 0; + for(; samples > 0; --samples, ++sp, ++dest) + { + val = (sp->ival << bitShift) + 128; + *dest = (kdu_byte)val; + } + break; + } + case 2: + { + /* TODO */ + } + default: + throw std::string("Not implemented"); + } + } + else + { + throw std::string("Unsupported/invalid line buffer"); + } +} + + +#if 0 +void +copyBlock(nrt_Uint8 *dest, kdu_block *block, int bitsPerSample, int outputBytes) +{ + size_t samples = (size_t)block->size.x * block->size.y; + size_t i; + kdu_int32 *inPtr = block->sample_buffer; + kdu_int32 bitShift, val; + + switch(outputBytes) + { + case 1: + { + bitShift = 32 - bitsPerSample; + for(; samples > 0; --samples, ++inPtr, dest += outputBytes) + { + val = (*inPtr << bitShift) + 128; + *dest = (kdu_byte)val; + } + break; + } + default: + throw std::string("Not yet implemented"); + } + +} +#endif + + +class UserContainer +{ +public: + + UserContainer() + { + } + + UserContainer(nrt_Uint32 width, + nrt_Uint32 height, + nrt_Uint32 bands, + nrt_Uint32 actualBitsPerPixel, + nrt_Uint32 tileWidth, + nrt_Uint32 tileHeight, + int imageType = J2K_TYPE_UNKNOWN, + bool isSigned = false) : + mWidth(width), + mHeight(height), + mComponents(bands), + mBitsPerPixel(actualBitsPerPixel), + mTileWidth(tileWidth), + mTileHeight(tileHeight), + mType(imageType), + mSigned(isSigned) + { + } + + nrt_Uint32 getNumComponents() const + { + return mComponents; + } + + nrt_Uint32 getWidth() const + { + return mWidth; + } + + nrt_Uint32 getHeight() const + { + return mHeight; + } + + nrt_Uint32 getComponentBytes() const + { + return (getActualBitsPerPixel() - 1) / 8 + 1; + } + + nrt_Uint32 getActualBitsPerPixel() const + { + return mBitsPerPixel; + } + + nrt_Uint32 getTileWidth() const + { + return mTileWidth; + } + + nrt_Uint32 getTileHeight() const + { + return mTileHeight; + } + + nrt_Uint32 getTilesX() const + { + return mWidth / mTileWidth + (mWidth % mTileWidth == 0 ? 0 : 1); + } + + nrt_Uint32 getTilesY() const + { + return mHeight / mTileHeight + (mHeight % mTileHeight == 0 ? 0 : 1); + } + + int getType() const + { + return mType; + } + + bool isSigned() const + { + return mSigned; + } + + +protected: + friend class Reader; + nrt_Uint32 mHeight, mWidth, mComponents, mBitsPerPixel; + nrt_Uint32 mTileWidth, mTileHeight; + int mType; + bool mSigned; +}; + + +class Reader +{ +public: + Reader(nrt_IOInterface *io) : mIO(io), mSource(NULL), mContainer(NULL) + { + init(); + } + ~Reader() + { + if (mSource) + delete mSource; + if (mCodestream) + { + mCodestream->destroy(); + delete mCodestream; + } + if (mContainer) + j2k_Container_destruct(&mContainer); + } + + void ownIO() + { + mSource->ownIO(); + } + + UserContainer* getUserContainer() const + { + return (UserContainer*)mContainer->data; + } + + j2k_Container* getContainer() const + { + return mContainer; + } + + nrt_Uint64 readTile(nrt_Uint32 tileX, nrt_Uint32 tileY, nrt_Uint8 **buf) + { + UserContainer *container = getUserContainer(); + nrt_Uint32 nComps = container->getNumComponents(); + nrt_Uint32 sampleSize = container->getComponentBytes(); + nrt_Uint64 lineSize = (nrt_Uint64)container->getTileWidth() * sampleSize; + nrt_Uint64 compSize = lineSize * container->getTileHeight(); + + nrt_Uint64 bufSize = compSize * nComps; + if (buf && !*buf) + { + *buf = (nrt_Uint8*)J2K_MALLOC(bufSize); + if (!*buf) + throw std::string("Out of memory"); + } + + kdu_coords tileIndex(tileX, tileY); + kdu_tile tile = mCodestream->open_tile(tileIndex, NULL); + + int tileComponents = tile.get_num_components(); + assert(tileComponents == nComps); + + nrt_Uint8 *bufPtr = *buf; + for(nrt_Uint32 i = 0; i < nComps; ++i) + { + kdu_tile_comp tileComponent = tile.access_component(i); + kdu_resolution tileRes = tileComponent.access_resolution(); + int bitDepth = tileComponent.get_bit_depth(); + + kdu_dims tileSize; + tileRes.get_dims(tileSize); + + bool shortBuffer = sampleSize <= 2; + kdu_line_buf line; + kdu_sample_allocator allocator; + line.pre_create(&allocator, tileSize.size.x, + tileComponent.get_reversible(), shortBuffer); + + kdu_pull_ifc engine; + if (tileRes.which() == 0) + engine = kdu_decoder(tileRes.access_subband(LL_BAND), + &allocator, shortBuffer); + else + engine = kdu_synthesis(tileRes, &allocator, shortBuffer); + allocator.finalize(); + line.create(); + + for(int y = 0; y < tileSize.size.y; y++ ) + { + engine.pull(line, true); + copyLine(bufPtr + y * lineSize, line, bitDepth, sampleSize); + } + engine.destroy(); + +#if 0 + int minBand; + nrt_Uint32 nBands = tileRes.get_valid_band_indices(minBand); + + for(nrt_Uint32 b = minBand; nBands > 0; --nBands, ++b) + { + kdu_subband tileBand = tileRes.access_subband(b); + kdu_dims validBlocks; + tileBand.get_valid_blocks(validBlocks); + + kdu_coords idx; + for(idx.y = 0; idx.y < validBlocks.size.y; ++idx.y) + { + for (idx.x = 0; idx.x < validBlocks.size.x; ++idx.x) + { + kdu_block *block = tileBand.open_block(idx + validBlocks.pos); + kdu_block_decoder decoder; + decoder.decode(block); + + copyBlock(bufPtr, block, bitDepth, sampleSize); + bufPtr += block->size.x * block->size.y; + tileBand.close_block(block); + } + } + } +#endif + } + + tile.close(); + return bufSize; + } + + +protected: + nrt_IOInterface *mIO; + IOStream *mSource; + kdu_codestream *mCodestream; + j2k_Container *mContainer; + nrt_Error mError; + + void init() + { + ErrorHandler errHandler; + kdu_customize_errors(&errHandler); + + mSource = new IOStream(mIO); + + if (!(mCodestream = new kdu_codestream)) + throw std::string("Unable to create codestream"); + + mCodestream->create(mSource); + mCodestream->apply_input_restrictions(0, 0, 0, 0, NULL, + KDU_WANT_OUTPUT_COMPONENTS); + + // create the j2k_Container + mContainer = (j2k_Container*) J2K_MALLOC(sizeof(j2k_Container)); + if (!mContainer) + throw std::string("Unable to create container"); + memset(mContainer, 0, sizeof(j2k_Container)); + mContainer->iface = &ContainerInterface; + + UserContainer *container = new UserContainer; + mContainer->data = container; + + // cache some metadata + container->mComponents = mCodestream->get_num_components(true); + + kdu_dims compSize; + mCodestream->get_dims(-1, compSize, true); + container->mWidth = (nrt_Uint32)(compSize.size.x); + container->mHeight = (nrt_Uint32)(compSize.size.y); + container->mBitsPerPixel = mCodestream->get_bit_depth(-1, true); + + kdu_dims partition; + mCodestream->get_tile_partition(partition); + container->mTileWidth = (nrt_Uint32)partition.size.x; + container->mTileHeight = (nrt_Uint32)partition.size.y; + +// kdu_dims indices; +// mCodestream->get_valid_tiles(indices); +// container->mTilesX = indices.size.x; +// container->mTilesY = indices.size.y; + + } +}; + +} +} + + +/******************************************************************************/ +/* CONTAINER */ +/******************************************************************************/ + +J2KPRIV( nrt_Uint32) +KakaduContainer_getTilesX(J2K_USER_DATA *data, nrt_Error *error) +{ + j2k::kakadu::UserContainer *impl = (j2k::kakadu::UserContainer*) data; + return impl->getTilesX(); +} + +J2KPRIV( nrt_Uint32) +KakaduContainer_getTilesY(J2K_USER_DATA *data, nrt_Error *error) +{ + j2k::kakadu::UserContainer *impl = (j2k::kakadu::UserContainer*) data; + return impl->getTilesY(); +} + +J2KPRIV( nrt_Uint32) +KakaduContainer_getTileWidth(J2K_USER_DATA *data, nrt_Error *error) +{ + j2k::kakadu::UserContainer *impl = (j2k::kakadu::UserContainer*) data; + return impl->getTileWidth(); +} + +J2KPRIV( nrt_Uint32) +KakaduContainer_getTileHeight(J2K_USER_DATA *data, nrt_Error *error) +{ + j2k::kakadu::UserContainer *impl = (j2k::kakadu::UserContainer*) data; + return impl->getTileHeight(); +} + +J2KPRIV( nrt_Uint32) +KakaduContainer_getWidth(J2K_USER_DATA *data, nrt_Error *error) +{ + j2k::kakadu::UserContainer *impl = (j2k::kakadu::UserContainer*) data; + return impl->getWidth(); +} + +J2KPRIV( nrt_Uint32) +KakaduContainer_getHeight(J2K_USER_DATA *data, nrt_Error *error) +{ + j2k::kakadu::UserContainer *impl = (j2k::kakadu::UserContainer*) data; + return impl->getHeight(); +} + +J2KPRIV( nrt_Uint32) +KakaduContainer_getNumComponents(J2K_USER_DATA *data, nrt_Error *error) +{ + j2k::kakadu::UserContainer *impl = (j2k::kakadu::UserContainer*) data; + return impl->getNumComponents(); +} + +J2KPRIV( nrt_Uint32) +KakaduContainer_getComponentBytes(J2K_USER_DATA *data, nrt_Error *error) +{ + j2k::kakadu::UserContainer *impl = (j2k::kakadu::UserContainer*) data; + return impl->getComponentBytes(); +} + +J2KPRIV( nrt_Uint32) +KakaduContainer_getComponentBits(J2K_USER_DATA *data, nrt_Error *error) +{ + j2k::kakadu::UserContainer *impl = (j2k::kakadu::UserContainer*) data; + return impl->getActualBitsPerPixel(); +} + +J2KPRIV( int) +KakaduContainer_getImageType(J2K_USER_DATA *data, nrt_Error *error) +{ + j2k::kakadu::UserContainer *impl = (j2k::kakadu::UserContainer*) data; + return impl->getType(); +} + +J2KPRIV( NRT_BOOL) +KakaduContainer_isSigned(J2K_USER_DATA *data, nrt_Error *error) +{ + j2k::kakadu::UserContainer *impl = (j2k::kakadu::UserContainer*) data; + return impl->isSigned(); +} + +J2KPRIV(void) +KakaduContainer_destruct(J2K_USER_DATA * data) +{ + if (data) + { + j2k::kakadu::UserContainer *impl = (j2k::kakadu::UserContainer*) data; + delete impl; + } +} + +/******************************************************************************/ +/* READER */ +/******************************************************************************/ + +J2KPRIV( NRT_BOOL) +KakaduReader_canReadTiles(J2K_USER_DATA *data, nrt_Error *error) +{ + return NRT_SUCCESS; +} + +J2KPRIV( nrt_Uint64) +KakaduReader_readTile(J2K_USER_DATA *data, nrt_Uint32 tileX, nrt_Uint32 tileY, + nrt_Uint8 **buf, nrt_Error *error) +{ + j2k::kakadu::Reader *reader = (j2k::kakadu::Reader*) data; + + try + { + return reader->readTile(tileX, tileY, buf); + } + catch(std::string &ex) + { + nrt_Error_init(error, ex.c_str(), NRT_CTXT, NRT_ERR_INVALID_OBJECT); + return 0; + } +} + +J2KPRIV( nrt_Uint64) +KakaduReader_readRegion(J2K_USER_DATA *data, nrt_Uint32 x0, nrt_Uint32 y0, + nrt_Uint32 x1, nrt_Uint32 y1, nrt_Uint8 **buf, + nrt_Error *error) +{ + j2k::kakadu::Reader *reader = (j2k::kakadu::Reader*) data; + // TODO + return 0; +} + +J2KPRIV( j2k_Container*) +KakaduReader_getContainer(J2K_USER_DATA *data, nrt_Error *error) +{ + j2k::kakadu::Reader *reader = (j2k::kakadu::Reader*) data; + return reader->getContainer(); +} + +J2KPRIV(void) +KakaduReader_destruct(J2K_USER_DATA * data) +{ + if (data) + { + j2k::kakadu::UserContainer *impl = (j2k::kakadu::UserContainer*) data; + delete impl; + } +} + +/******************************************************************************/ +/* WRITER */ +/******************************************************************************/ + +J2KPRIV( NRT_BOOL) +KakaduWriter_setTile(J2K_USER_DATA *data, nrt_Uint32 tileX, nrt_Uint32 tileY, + nrt_Uint8 *buf, nrt_Uint32 tileSize, nrt_Error *error) +{ + nrt_Error_init(error, "Writer->setTile not yet implemented", + NRT_CTXT, NRT_ERR_INVALID_OBJECT); + //TODO + return NRT_FAILURE; +} + +J2KPRIV( NRT_BOOL) +KakaduWriter_write(J2K_USER_DATA *data, nrt_IOInterface *io, nrt_Error *error) +{ + nrt_Error_init(error, "Writer->write not yet implemented", + NRT_CTXT, NRT_ERR_INVALID_OBJECT); + // TODO + return NRT_FAILURE; +} + +J2KPRIV( j2k_Container*) +KakaduWriter_getContainer(J2K_USER_DATA *data, nrt_Error *error) +{ + nrt_Error_init(error, "Writer->getContainer not yet implemented", + NRT_CTXT, NRT_ERR_INVALID_OBJECT); + //TODO + return NULL; +} + +J2KPRIV(void) +KakaduWriter_destruct(J2K_USER_DATA * data) +{ + //TODO +} + +/******************************************************************************/ +/******************************************************************************/ +/* PUBLIC FUNCTIONS */ +/******************************************************************************/ +/******************************************************************************/ + +J2KAPI(j2k_Reader*) j2k_Reader_open(const char *fname, nrt_Error *error) +{ + j2k_Reader *reader = NULL; + nrt_IOHandle handle; + nrt_IOInterface *io = NULL; + + if (!fname) + { + nrt_Error_init(error, "NULL filename", NRT_CTXT, NRT_ERR_INVALID_OBJECT); + goto CATCH_ERROR; + } + + handle = nrt_IOHandle_create(fname, NRT_ACCESS_READONLY, NRT_OPEN_EXISTING, + error); + if (NRT_INVALID_HANDLE(handle)) + { + nrt_Error_init(error, "Invalid IO handle", NRT_CTXT, + NRT_ERR_INVALID_OBJECT); + goto CATCH_ERROR; + } + + if (!(io = nrt_IOHandleAdapter_construct(handle, error))) + goto CATCH_ERROR; + + if (!(reader = j2k_Reader_openIO(io, error))) + goto CATCH_ERROR; + + ((j2k::kakadu::Reader*) reader->data)->ownIO(); + + return reader; + + CATCH_ERROR: + { + if (io) + nrt_IOInterface_destruct(&io); + if (reader) + j2k_Reader_destruct(&reader); + return NULL; + } +} + +J2KAPI(j2k_Reader*) j2k_Reader_openIO(nrt_IOInterface *io, nrt_Error *error) +{ + j2k_Reader *reader = NULL; + reader = (j2k_Reader *) J2K_MALLOC(sizeof(j2k_Reader)); + if (!reader) + { + nrt_Error_init(error, NRT_STRERROR(NRT_ERRNO), NRT_CTXT, NRT_ERR_MEMORY); + goto CATCH_ERROR; + } + memset(reader, 0, sizeof(j2k_Reader)); + + try + { + if (!(reader->data = new j2k::kakadu::Reader(io))) + goto CATCH_ERROR; + } + catch(std::string& ex) + { + nrt_Error_init(error, ex.c_str(), NRT_CTXT, NRT_ERR_UNK); + goto CATCH_ERROR; + } + + reader->iface = &ReaderInterface; + return reader; + + CATCH_ERROR: + { + if (reader) + { + j2k_Reader_destruct(&reader); + } + return NULL; + } +} + +J2KAPI(j2k_Container*) j2k_Container_construct(nrt_Uint32 width, + nrt_Uint32 height, + nrt_Uint32 bands, + nrt_Uint32 actualBitsPerPixel, + nrt_Uint32 tileWidth, + nrt_Uint32 tileHeight, + int imageType, + int isSigned, + nrt_Error *error) +{ + j2k_Container *container = NULL; + j2k::kakadu::UserContainer *userContainer = NULL; + + container = (j2k_Container*) J2K_MALLOC(sizeof(j2k_Container)); + if (!container) + { + nrt_Error_init(error, NRT_STRERROR(NRT_ERRNO), NRT_CTXT, NRT_ERR_MEMORY); + goto CATCH_ERROR; + } + memset(container, 0, sizeof(j2k_Container)); + + if (!(container->data = new j2k::kakadu::UserContainer(width, height, bands, + actualBitsPerPixel, + tileWidth, + tileHeight, + imageType, + isSigned))) + goto CATCH_ERROR; + + container->iface = &ContainerInterface; + + return container; + + CATCH_ERROR: + { + if (container) + { + j2k_Container_destruct(&container); + } + return NULL; + } +} + +J2KAPI(j2k_Writer*) j2k_Writer_construct(j2k_Container *container, + nrt_Error *error) +{ + j2k_Writer *writer = NULL; +// j2k::kakadu::UserContainer *userContainer = NULL; +// + writer = (j2k_Writer*) J2K_MALLOC(sizeof(j2k_Container)); + if (!writer) + { + nrt_Error_init(error, NRT_STRERROR(NRT_ERRNO), NRT_CTXT, NRT_ERR_MEMORY); + goto CATCH_ERROR; + } + memset(writer, 0, sizeof(j2k_Writer)); +// +// if (!(container->data = new j2k::kakadu::UserContainer(width, height, bands, +// actualBitsPerPixel, +// tileWidth, +// tileHeight, +// imageType, +// isSigned))) +// goto CATCH_ERROR; +// + writer->iface = &WriterInterface; + + return writer; + + CATCH_ERROR: + { + if (writer) + { + j2k_Writer_destruct(&writer); + } + return NULL; + } +} + +#endif diff --git a/modules/c/j2k/source/OpenJPEGImpl.c b/modules/c/j2k/source/OpenJPEGImpl.c new file mode 100644 index 000000000..d8d1e8ee7 --- /dev/null +++ b/modules/c/j2k/source/OpenJPEGImpl.c @@ -0,0 +1,1261 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifdef HAVE_OPENJPEG_H + +#include + +#include "j2k/Container.h" +#include "j2k/Reader.h" +#include "j2k/Writer.h" + +#include + + +/******************************************************************************/ +/* TYPES & DECLARATIONS */ +/******************************************************************************/ + +#define OPENJPEG_STREAM_SIZE 1024 + +typedef struct _IOControl +{ + nrt_IOInterface *io; + nrt_Off offset; + nrt_Off length; + int isRead; + nrt_Error error; +} IOControl; + + +typedef struct _OpenJPEGReaderImpl +{ + opj_dparameters_t parameters; + nrt_Off ioOffset; + nrt_IOInterface *io; + int ownIO; + j2k_Container *container; + IOControl userData; +} OpenJPEGReaderImpl; + +typedef struct _OpenJPEGWriterImpl +{ + j2k_Container *container; + opj_codec_t *codec; + opj_image_t *image; + char *compressedBuf; + nrt_IOInterface *compressed; + opj_stream_t *stream; + IOControl userData; +} OpenJPEGWriterImpl; + +typedef struct _OpenJPEGError +{ + nrt_Error *error; + void *context; +} OpenJPEGError; + +J2KPRIV(OPJ_SIZE_T) implStreamRead(void* buf, OPJ_SIZE_T bytes, void *data); +J2KPRIV(OPJ_BOOL) implStreamSeek(OPJ_OFF_T bytes, void *data); +J2KPRIV(OPJ_OFF_T) implStreamSkip(OPJ_OFF_T bytes, void *data); +J2KPRIV(OPJ_SIZE_T) implStreamWrite(void *buf, OPJ_SIZE_T bytes, void *data); + + +J2KPRIV( NRT_BOOL ) OpenJPEGReader_canReadTiles(J2K_USER_DATA *, nrt_Error *); +J2KPRIV( nrt_Uint64) OpenJPEGReader_readTile(J2K_USER_DATA *, nrt_Uint32, + nrt_Uint32, nrt_Uint8 **, + nrt_Error *); +J2KPRIV( nrt_Uint64) OpenJPEGReader_readRegion(J2K_USER_DATA *, nrt_Uint32, + nrt_Uint32, nrt_Uint32, + nrt_Uint32, nrt_Uint8 **, + nrt_Error *); +J2KPRIV( j2k_Container*) OpenJPEGReader_getContainer(J2K_USER_DATA *, nrt_Error *); +J2KPRIV(void) OpenJPEGReader_destruct(J2K_USER_DATA *); + +static j2k_IReader ReaderInterface = {&OpenJPEGReader_canReadTiles, + &OpenJPEGReader_readTile, + &OpenJPEGReader_readRegion, + &OpenJPEGReader_getContainer, + &OpenJPEGReader_destruct }; + +J2KPRIV( NRT_BOOL) OpenJPEGWriter_setTile(J2K_USER_DATA *, + nrt_Uint32, nrt_Uint32, + const nrt_Uint8 *, nrt_Uint32, + nrt_Error *); +J2KPRIV( NRT_BOOL) OpenJPEGWriter_write(J2K_USER_DATA *, nrt_IOInterface *, + nrt_Error *); +J2KPRIV( j2k_Container*) OpenJPEGWriter_getContainer(J2K_USER_DATA *, nrt_Error *); +J2KPRIV(void) OpenJPEGWriter_destruct(J2K_USER_DATA *); + +static j2k_IWriter WriterInterface = {&OpenJPEGWriter_setTile, + &OpenJPEGWriter_write, + &OpenJPEGWriter_getContainer, + &OpenJPEGWriter_destruct }; + + +J2KPRIV(void) OpenJPEG_cleanup(opj_stream_t **, opj_codec_t **, opj_image_t **); +J2KPRIV( J2K_BOOL) OpenJPEG_initImage(OpenJPEGWriterImpl *, j2k_WriterOptions *, + nrt_Error *); + +J2KPRIV(void) OpenJPEG_errorHandler(const char* msg, void* data) +{ + nrt_Error* error = (nrt_Error*)data; + /* Initialize the first message, otherwise the message will be + overridden up the stack */ + if(strlen(error->message) == 0) + { + nrt_Error_init(error, msg, NRT_CTXT, NRT_ERR_INVALID_OBJECT); + } +} + +/******************************************************************************/ +/* IO */ +/******************************************************************************/ + +J2KAPI(opj_stream_t*) +OpenJPEG_createIO(nrt_IOInterface* io, + IOControl* ioControl, + nrt_Off length, + int isInput, + nrt_Error *error) +{ + opj_stream_t *stream = NULL; + + stream = opj_stream_create(OPENJPEG_STREAM_SIZE, isInput); + if (!stream) + { + nrt_Error_init(error, "Error creating openjpeg stream", NRT_CTXT, + NRT_ERR_MEMORY); + } + else + { + ioControl->io = io; + ioControl->offset = nrt_IOInterface_tell(io, error); + if (length > 0) + ioControl->length = length; + else + ioControl->length = nrt_IOInterface_getSize(io, error) + - ioControl->offset; + + opj_stream_set_user_data(stream, ioControl); + opj_stream_set_read_function(stream, implStreamRead); + opj_stream_set_seek_function(stream, implStreamSeek); + opj_stream_set_skip_function(stream, implStreamSkip); + opj_stream_set_write_function(stream, implStreamWrite); + } + return stream; +} + +J2KPRIV(OPJ_SIZE_T) implStreamRead(void* buf, OPJ_SIZE_T bytes, void *data) +{ + IOControl *ctrl = (IOControl*)data; + nrt_Off offset, alreadyRead; + OPJ_SIZE_T bytesLeft; + OPJ_SIZE_T toRead; + + offset = nrt_IOInterface_tell(ctrl->io, &ctrl->error); + assert(offset >= ctrl->offset); /* probably not a good idea, but need it */ + + alreadyRead = offset - ctrl->offset; + bytesLeft = alreadyRead >= ctrl->length ? + 0 : (OPJ_SIZE_T)(ctrl->length - alreadyRead); + toRead = bytesLeft < bytes ? bytesLeft : bytes; + if (toRead <= 0 || !nrt_IOInterface_read( + ctrl->io, (char*)buf, toRead, &ctrl->error)) + { + return 0; + } + return toRead; +} + +J2KPRIV(OPJ_BOOL) implStreamSeek(OPJ_OFF_T bytes, void *data) +{ + IOControl *ctrl = (IOControl*)data; + if (!NRT_IO_SUCCESS(nrt_IOInterface_seek(ctrl->io, + ctrl->offset + bytes, + NRT_SEEK_SET, + &ctrl->error))) + { + return 0; + } + return 1; +} + +J2KPRIV(OPJ_OFF_T) implStreamSkip(OPJ_OFF_T bytes, void *data) +{ + IOControl *ctrl = (IOControl*)data; + if (bytes < 0) + { + return 0; + } + if (!NRT_IO_SUCCESS(nrt_IOInterface_seek(ctrl->io, + bytes, + NRT_SEEK_CUR, + &ctrl->error))) + { + return -1; + } + return bytes; +} + +J2KPRIV(OPJ_SIZE_T) implStreamWrite(void *buf, OPJ_SIZE_T bytes, void *data) +{ + IOControl *ctrl = (IOControl*)data; + if (bytes == 0) + { + return 0; + } + if (!nrt_IOInterface_write(ctrl->io, (const char*)buf, + bytes, &ctrl->error)) + { + return (OPJ_SIZE_T)-1; + } + return bytes; +} + +J2KPRIV(void) +OpenJPEG_cleanup(opj_stream_t **stream, opj_codec_t **codec, + opj_image_t **image) +{ + if (stream && *stream) + { + opj_stream_destroy(*stream); + *stream = NULL; + } + if (codec && *codec) + { + opj_destroy_codec(*codec); + *codec = NULL; + } + if (image && *image) + { + opj_image_destroy(*image); + *image = NULL; + } +} + +/******************************************************************************/ +/* UTILITIES */ +/******************************************************************************/ + +J2KPRIV( NRT_BOOL) +OpenJPEG_setup(OpenJPEGReaderImpl *impl, opj_stream_t **stream, + opj_codec_t **codec, nrt_Error *error) +{ + if (!NRT_IO_SUCCESS(nrt_IOInterface_seek(impl->io, + impl->ioOffset, + NRT_SEEK_SET, + error))) + { + goto CATCH_ERROR; + } + + if (!(*stream = OpenJPEG_createIO(impl->io, &impl->userData, 0, 1, error))) + { + goto CATCH_ERROR; + } + + if (!(*codec = opj_create_decompress(OPJ_CODEC_J2K))) + { + nrt_Error_init(error, "Error creating OpenJPEG codec", NRT_CTXT, + NRT_ERR_INVALID_OBJECT); + goto CATCH_ERROR; + } + + memset(error->message, 0, NRT_MAX_EMESSAGE); + if(!opj_set_error_handler(*codec, + OpenJPEG_errorHandler, + error)) + { + nrt_Error_init(error, "Unable to set OpenJPEG error handler", NRT_CTXT, + NRT_ERR_UNK); + goto CATCH_ERROR; + } + + opj_set_default_decoder_parameters(&impl->parameters); + + if (!opj_setup_decoder(*codec, &impl->parameters)) + { + /*nrt_Error_init(error, "Error setting up openjpeg decoder", NRT_CTXT, + NRT_ERR_UNK);*/ + goto CATCH_ERROR; + } + + return NRT_SUCCESS; + + CATCH_ERROR: + { + OpenJPEG_cleanup(stream, codec, NULL); + return NRT_FAILURE; + } +} + +J2KPRIV( NRT_BOOL) +OpenJPEG_readHeader(OpenJPEGReaderImpl *impl, nrt_Error *error) +{ + opj_stream_t *stream = NULL; + opj_image_t *image = NULL; + opj_codec_t *codec = NULL; + opj_codestream_info_v2_t* codeStreamInfo = NULL; + NRT_BOOL rc = NRT_SUCCESS; + OPJ_UINT32 tileWidth, tileHeight; + OPJ_UINT32 imageWidth, imageHeight; + + if (!OpenJPEG_setup(impl, &stream, &codec, error)) + { + goto CATCH_ERROR; + } + + if (!opj_read_header(stream, codec, &image)) + { + /*nrt_Error_init(error, "Error reading header", NRT_CTXT, NRT_ERR_UNK);*/ + goto CATCH_ERROR; + } + + codeStreamInfo = opj_get_cstr_info(codec); + if (!codeStreamInfo) + { + /*nrt_Error_init(error, "Error reading code stream", NRT_CTXT, NRT_ERR_UNK);*/ + goto CATCH_ERROR; + } + tileWidth = codeStreamInfo->tdx; + tileHeight = codeStreamInfo->tdy; + + /* sanity checking */ + if (!image) + { + nrt_Error_init(error, "NULL image after reading header", NRT_CTXT, + NRT_ERR_UNK); + goto CATCH_ERROR; + } + + if (image->x0 >= image->x1 || image->y0 >= image->y1) + { + nrt_Error_init(error, "Invalid image offsets", NRT_CTXT, NRT_ERR_UNK); + goto CATCH_ERROR; + } + if (image->numcomps == 0) + { + nrt_Error_init(error, "No image components found", NRT_CTXT, + NRT_ERR_UNK); + goto CATCH_ERROR; + } + + /* TODO: We need special handling that's not implemented in readTile() to + * accommodate partial tiles with more than one band. */ + imageWidth = image->x1 - image->x0; + imageHeight = image->y1 - image->y0; + if (image->numcomps > 1 && + (imageWidth % tileWidth != 0 || imageHeight % tileHeight != 0)) + { + nrt_Error_init(error, "No image components found", NRT_CTXT, + NRT_ERR_UNK); + goto CATCH_ERROR; + } + + if (!impl->container) + { + /* initialize the container */ + nrt_Uint32 idx; + j2k_Component **components = NULL; + int imageType; + + if (!(components = (j2k_Component**)J2K_MALLOC( + sizeof(j2k_Component*) * image->numcomps))) + { + nrt_Error_init(error, NRT_STRERROR(NRT_ERRNO), NRT_CTXT, + NRT_ERR_MEMORY); + goto CATCH_ERROR; + } + + for(idx = 0; idx < image->numcomps; ++idx) + { + opj_image_comp_t cmp = image->comps[idx]; + if (!(components[idx] = j2k_Component_construct(cmp.w, cmp.h, + cmp.prec, cmp.sgnd, + cmp.x0, cmp.y0, + cmp.dx, cmp.dy, + error))) + { + goto CATCH_ERROR; + } + } + + switch(image->color_space) + { + case OPJ_CLRSPC_SRGB: + imageType = J2K_TYPE_RGB; + break; + case OPJ_CLRSPC_GRAY: + imageType = J2K_TYPE_MONO; + break; + default: + imageType = J2K_TYPE_UNKNOWN; + } + + if (!(impl->container = j2k_Container_construct(image->x1 - image->x0, + image->y1 - image->y0, + image->numcomps, + components, + tileWidth, tileHeight, + imageType, error))) + { + goto CATCH_ERROR; + } + } + + goto CLEANUP; + + CATCH_ERROR: + { + rc = NRT_FAILURE; + } + + CLEANUP: + { + opj_destroy_cstr_info(&codeStreamInfo); + OpenJPEG_cleanup(&stream, &codec, &image); + } + return rc; +} + +J2KPRIV( NRT_BOOL) OpenJPEG_initImage(OpenJPEGWriterImpl *impl, + j2k_WriterOptions *writerOps, + nrt_Error *error) +{ + NRT_BOOL rc = NRT_SUCCESS; + nrt_Uint32 i, nComponents, height, width, tileHeight, tileWidth; + nrt_Uint32 nBytes; + j2k_Component *component = NULL; + size_t uncompressedSize; + int imageType; + opj_cparameters_t encoderParams; + opj_image_cmptparm_t *cmptParams; + OPJ_COLOR_SPACE colorSpace; + + nComponents = j2k_Container_getNumComponents(impl->container, error); + width = j2k_Container_getWidth(impl->container, error); + height = j2k_Container_getHeight(impl->container, error); + tileWidth = j2k_Container_getTileWidth(impl->container, error); + tileHeight = j2k_Container_getTileHeight(impl->container, error); + imageType = j2k_Container_getImageType(impl->container, error); + + /* Set up the encoder parameters. This defaults to lossless. */ + /* TODO allow overrides somehow? */ + opj_set_default_encoder_parameters(&encoderParams); + + /* For now we are enforcing lossless compression. If we have a better + * way to allow overrides in the future, uncomment out the tcp_rates logic + * below (tcp_rates[0] == 0 via opj_set_default_encoder_parameters()). + * Also consider setting encoderParams.irreversible = 1; to use the + * lossy DWT 9-7 instead of the reversible 5-3. + */ + + /*if (writerOps && writerOps->compressionRatio > 0.0001) + encoderParams.tcp_rates[0] = 1.0 / writerOps->compressionRatio; + else + encoderParams.tcp_rates[0] = 4.0; + */ + + /* TODO: These two lines should not be necessary when using lossless + * encoding but appear to be needed (at least in OpenJPEG 2.0) - + * otherwise we get a seg fault. + * The sample opj_compress.c is doing the same thing with a comment + * indicating that it's a bug. */ + ++encoderParams.tcp_numlayers; + encoderParams.cp_disto_alloc = 1; + + if (writerOps && writerOps->numResolutions > 0) + { + encoderParams.numresolution = writerOps->numResolutions; + /* Note, if this isn't set right (see below) it will error out */ + } + else + { + /* + OpenJPEG defaults this to 6, but that causes the compressor + to fail if the tile sizes are less than 2^6. So we adjust this + down if necessary. + */ + const double logTwo = log(2); + const OPJ_UINT32 minX = (OPJ_UINT32)floor(log(tileWidth) / logTwo); + const OPJ_UINT32 minY = (OPJ_UINT32)floor(log(tileHeight) / logTwo); + const OPJ_UINT32 minXY = (minX < minY) ? minX : minY; + if (minXY < encoderParams.numresolution) + { + encoderParams.numresolution = minXY; + } + } + + /* Turn on tiling */ + encoderParams.tile_size_on = 1; + encoderParams.cp_tx0 = 0; + encoderParams.cp_ty0 = 0; + encoderParams.cp_tdx = tileWidth; + encoderParams.cp_tdy = tileHeight; + + if (!(cmptParams = (opj_image_cmptparm_t*)J2K_MALLOC(sizeof( + opj_image_cmptparm_t) * nComponents))) + { + nrt_Error_init(error, NRT_STRERROR(NRT_ERRNO), NRT_CTXT, + NRT_ERR_MEMORY); + goto CATCH_ERROR; + } + memset(cmptParams, 0, sizeof(opj_image_cmptparm_t) * nComponents); + + for(i = 0; i < nComponents; ++i) + { + component = j2k_Container_getComponent(impl->container, i, error); + cmptParams[i].w = j2k_Component_getWidth(component, error); + cmptParams[i].h = j2k_Component_getHeight(component, error); + cmptParams[i].prec = j2k_Component_getPrecision(component, error); + cmptParams[i].x0 = j2k_Component_getOffsetX(component, error); + cmptParams[i].y0 = j2k_Component_getOffsetY(component, error); + cmptParams[i].dx = j2k_Component_getSeparationX(component, error); + cmptParams[i].dy = j2k_Component_getSeparationY(component, error); + cmptParams[i].sgnd = j2k_Component_isSigned(component, error); + } + + nBytes = (j2k_Container_getPrecision(impl->container, error) - 1) / 8 + 1; + uncompressedSize = width * height * nComponents * nBytes; + + /* this is not ideal, but there is really no other way */ + if (!(impl->compressedBuf = (char*)J2K_MALLOC(uncompressedSize))) + { + nrt_Error_init(error, NRT_STRERROR(NRT_ERRNO), NRT_CTXT, + NRT_ERR_MEMORY); + goto CATCH_ERROR; + } + if (!(impl->compressed = nrt_BufferAdapter_construct(impl->compressedBuf, + uncompressedSize, 1, + error))) + { + goto CATCH_ERROR; + } + + if (!(impl->stream = OpenJPEG_createIO(impl->compressed, &impl->userData, + 0, 0, error))) + { + goto CATCH_ERROR; + } + + + switch(imageType) + { + case J2K_TYPE_RGB: + colorSpace = OPJ_CLRSPC_SRGB; + break; + default: + colorSpace = OPJ_CLRSPC_GRAY; + } + + if (!(impl->codec = opj_create_compress(OPJ_CODEC_J2K))) + { + nrt_Error_init(error, "Error creating OpenJPEG codec", NRT_CTXT, + NRT_ERR_INVALID_OBJECT); + goto CATCH_ERROR; + } + if (!(impl->image = opj_image_tile_create(nComponents, cmptParams, + colorSpace))) + { + nrt_Error_init(error, "Error creating OpenJPEG image", NRT_CTXT, + NRT_ERR_INVALID_OBJECT); + goto CATCH_ERROR; + } + + /* for some reason we must also explicitly specify these in the image... */ + impl->image->numcomps = nComponents; + impl->image->x0 = 0; + impl->image->y0 = 0; + impl->image->x1 = width; + impl->image->y1 = height; + impl->image->color_space = colorSpace; + + memset(error->message, 0, NRT_MAX_EMESSAGE); + if(!opj_set_error_handler(impl->codec, + OpenJPEG_errorHandler, + error)) + { + nrt_Error_init(error, "Unable to set OpenJPEG error handler", NRT_CTXT, + NRT_ERR_UNK); + goto CATCH_ERROR; + } + + if (!opj_setup_encoder(impl->codec, &encoderParams, impl->image)) + { + /*nrt_Error_init(error, "Error setting up OpenJPEG decoder", NRT_CTXT, + NRT_ERR_INVALID_OBJECT);*/ + goto CATCH_ERROR; + } + + if (!opj_start_compress(impl->codec, impl->image, impl->stream)) + { + /*nrt_Error_init(error, "Error starting OpenJPEG compression", NRT_CTXT, + NRT_ERR_INVALID_OBJECT);*/ + goto CATCH_ERROR; + } + + goto CLEANUP; + + CATCH_ERROR: + { + rc = NRT_FAILURE; + } + + CLEANUP: + { + if (cmptParams) + J2K_FREE(cmptParams); + } + + return rc; +} + + +/******************************************************************************/ +/* READER */ +/******************************************************************************/ + +J2KPRIV( NRT_BOOL) +OpenJPEGReader_canReadTiles(J2K_USER_DATA *data, nrt_Error *error) +{ + return NRT_SUCCESS; +} + +J2KPRIV( nrt_Uint64) +OpenJPEGReader_readTile(J2K_USER_DATA *data, nrt_Uint32 tileX, nrt_Uint32 tileY, + nrt_Uint8 **buf, nrt_Error *error) +{ + OpenJPEGReaderImpl *impl = (OpenJPEGReaderImpl*) data; + + opj_stream_t *stream = NULL; + opj_image_t *image = NULL; + opj_codec_t *codec = NULL; + nrt_Uint32 bufSize; + const OPJ_UINT32 tileWidth = j2k_Container_getTileWidth(impl->container, error); + const OPJ_UINT32 tileHeight = j2k_Container_getTileHeight(impl->container, error); + size_t numBitsPerPixel = 0; + size_t numBytesPerPixel = 0; + nrt_Uint64 fullBufSize = 0; + + if (!OpenJPEG_setup(impl, &stream, &codec, error)) + { + goto CATCH_ERROR; + } + + /* unfortunately, we need to read the header every time ... */ + if (!opj_read_header(stream, codec, &image)) + { + /*nrt_Error_init(error, "Error reading header", NRT_CTXT, NRT_ERR_UNK);*/ + goto CATCH_ERROR; + } + + /* only decode what we want */ + if (!opj_set_decode_area(codec, image, tileWidth * tileX, tileHeight * tileY, + tileWidth * (tileX + 1), tileHeight * (tileY + 1))) + { + /*nrt_Error_init(error, "Error decoding area", NRT_CTXT, NRT_ERR_UNK);*/ + goto CATCH_ERROR; + } + + { + int keepGoing; + OPJ_UINT32 tileIndex, nComponents; + OPJ_INT32 tileX0, tileY0, tileX1, tileY1; + + if (!opj_read_tile_header(codec, stream, &tileIndex, &bufSize, &tileX0, + &tileY0, &tileX1, &tileY1, &nComponents, + &keepGoing)) + { + /*nrt_Error_init(error, "Error reading tile header", NRT_CTXT, + NRT_ERR_UNK);*/ + goto CATCH_ERROR; + } + + if (keepGoing) + { + /* TODO: The way blockIO->cntl->blockOffsetInc is currently + * implemented in ImageIO.c corresponds with how a + * non-compressed partial block would be laid out in a + * NITF - the actual extra columns would have been read. + * Not sure how the J2K data is laid out on disk but + * OpenJPEG is hiding this from us if the extra columns are + * present there. So whenever we get a partial tile that + * isn't at the full width, we need to add in these extra + * columns of 0's ourselves. Potentially we could update + * ImageIO.c to not require this instead. Note that we + * don't need to pad out the extra rows for a partial block + * that isn't the full height because ImageIO will never try + * to memcpy these in - we only need to get the stride to + * work out correctly. + */ + const OPJ_UINT32 thisTileWidth = tileX1 - tileX0; + const OPJ_UINT32 thisTileHeight = tileY1 - tileY0; + if (thisTileWidth < tileWidth) + { + /* TODO: The current approach below only works for single band + * imagery. For RGB data, I believe it is stored as all + * red, then all green, then all blue, so we would need + * a temp buffer rather than reusing the current buffer. + */ + if (nComponents != 1) + { + nrt_Error_init( + error, + "Partial tile width not implemented for multi-band", + NRT_CTXT, NRT_ERR_UNK); + goto CATCH_ERROR; + } + + numBitsPerPixel = + j2k_Container_getPrecision(impl->container, error); + numBytesPerPixel = + (numBitsPerPixel / 8) + (numBitsPerPixel % 8 != 0); + fullBufSize = tileWidth * thisTileHeight * numBytesPerPixel; + } + else + { + fullBufSize = bufSize; + } + + if (buf && !*buf) + { + *buf = (nrt_Uint8*)J2K_MALLOC(fullBufSize); + if (!*buf) + { + nrt_Error_init(error, NRT_STRERROR(NRT_ERRNO), NRT_CTXT, + NRT_ERR_MEMORY); + goto CATCH_ERROR; + } + } + + if (!opj_decode_tile_data(codec, tileIndex, *buf, bufSize, stream)) + { + /*nrt_Error_init(error, "Error decoding tile", NRT_CTXT, + NRT_ERR_UNK);*/ + goto CATCH_ERROR; + } + + if (thisTileWidth < tileWidth) + { + /* We have a tile that isn't as wide as it "should" be + * Need to add in the extra columns ourselves. By marching + * through the rows backwards, we can do this in place. + */ + const size_t srcStride = thisTileWidth * numBytesPerPixel; + const size_t destStride = tileWidth * numBytesPerPixel; + const size_t numLeftoverBytes = destStride - srcStride; + OPJ_UINT32 lastRow = thisTileHeight - 1; + size_t srcOffset = lastRow * srcStride; + size_t destOffset = lastRow * destStride; + OPJ_UINT32 ii; + nrt_Uint8* bufPtr = *buf; + + for (ii = 0; + ii < thisTileHeight; + ++ii, srcOffset -= srcStride, destOffset -= destStride) + { + nrt_Uint8* const dest = bufPtr + destOffset; + memmove(dest, bufPtr + srcOffset, srcStride); + memset(dest + srcStride, 0, numLeftoverBytes); + } + } + } + } + + goto CLEANUP; + + CATCH_ERROR: + { + fullBufSize = 0; + } + + CLEANUP: + { + OpenJPEG_cleanup(&stream, &codec, &image); + } + return fullBufSize; +} + +J2KPRIV( nrt_Uint64) +OpenJPEGReader_readRegion(J2K_USER_DATA *data, nrt_Uint32 x0, nrt_Uint32 y0, + nrt_Uint32 x1, nrt_Uint32 y1, nrt_Uint8 **buf, + nrt_Error *error) +{ + OpenJPEGReaderImpl *impl = (OpenJPEGReaderImpl*) data; + + opj_stream_t *stream = NULL; + opj_image_t *image = NULL; + opj_codec_t *codec = NULL; + nrt_Uint64 bufSize; + nrt_Uint64 offset = 0; + nrt_Uint32 componentBytes, nComponents; + + if (!OpenJPEG_setup(impl, &stream, &codec, error)) + { + goto CATCH_ERROR; + } + + /* unfortunately, we need to read the header every time ... */ + if (!opj_read_header(stream, codec, &image)) + { + /*nrt_Error_init(error, "Error reading header", NRT_CTXT, NRT_ERR_UNK);*/ + goto CATCH_ERROR; + } + + if (x1 == 0) + x1 = j2k_Container_getWidth(impl->container, error); + if (y1 == 0) + y1 = j2k_Container_getHeight(impl->container, error); + + /* only decode what we want */ + if (!opj_set_decode_area(codec, image, x0, y0, x1, y1)) + { + /*nrt_Error_init(error, "Error decoding area", NRT_CTXT, NRT_ERR_UNK);*/ + goto CATCH_ERROR; + } + + nComponents = j2k_Container_getNumComponents(impl->container, error); + componentBytes = (j2k_Container_getPrecision(impl->container, error) - 1) / 8 + 1; + bufSize = (nrt_Uint64)(x1 - x0) * (y1 - y0) * componentBytes * nComponents; + if (buf && !*buf) + { + *buf = (nrt_Uint8*)J2K_MALLOC(bufSize); + if (!*buf) + { + nrt_Error_init(error, NRT_STRERROR(NRT_ERRNO), NRT_CTXT, + NRT_ERR_MEMORY); + goto CATCH_ERROR; + } + } + + { + int keepGoing; + OPJ_UINT32 tileIndex, reqSize; + OPJ_INT32 tileX0, tileY0, tileX1, tileY1; + + do + { + if (!opj_read_tile_header(codec, stream, &tileIndex, &reqSize, &tileX0, + &tileY0, &tileX1, &tileY1, &nComponents, + &keepGoing)) + { + /*nrt_Error_init(error, "Error reading tile header", NRT_CTXT, + NRT_ERR_UNK);*/ + goto CATCH_ERROR; + } + + if (keepGoing) + { + if (!opj_decode_tile_data(codec, tileIndex, (*buf + offset), + reqSize, stream)) + { + /*nrt_Error_init(error, "Error decoding tile", NRT_CTXT, + NRT_ERR_UNK);*/ + goto CATCH_ERROR; + } + offset += reqSize; + } + } + while (keepGoing); + } + + goto CLEANUP; + + CATCH_ERROR: + { + bufSize = 0; + } + + CLEANUP: + { + OpenJPEG_cleanup(&stream, &codec, &image); + } + return bufSize; +} + +J2KPRIV( j2k_Container*) +OpenJPEGReader_getContainer(J2K_USER_DATA *data, nrt_Error *error) +{ + OpenJPEGReaderImpl *impl = (OpenJPEGReaderImpl*) data; + return impl->container; +} + +J2KPRIV(void) +OpenJPEGReader_destruct(J2K_USER_DATA * data) +{ + if (data) + { + OpenJPEGReaderImpl* const impl = (OpenJPEGReaderImpl*) data; + if (impl->io && impl->ownIO) + { + nrt_IOInterface_destruct(&impl->io); + impl->io = NULL; + } + if(impl->container) + { + j2k_Container_destruct(&impl->container); + impl->container = NULL; + } + J2K_FREE(data); + } +} + +/******************************************************************************/ +/* WRITER */ +/******************************************************************************/ + +J2KPRIV( NRT_BOOL) +OpenJPEGWriter_setTile(J2K_USER_DATA *data, nrt_Uint32 tileX, nrt_Uint32 tileY, + const nrt_Uint8 *buf, nrt_Uint32 tileSize, + nrt_Error *error) +{ + OpenJPEGWriterImpl *impl = (OpenJPEGWriterImpl*) data; + NRT_BOOL rc = NRT_SUCCESS; + nrt_Uint32 xTiles, yTiles, tileIndex, width, height, tileWidth, tileHeight; + nrt_Uint32 thisTileWidth, thisTileHeight, thisTileSize, nComponents, nBytes; + nrt_Uint8* newTileBuf = NULL; + + xTiles = j2k_Container_getTilesX(impl->container, error); + yTiles = j2k_Container_getTilesY(impl->container, error); + width = j2k_Container_getWidth(impl->container, error); + height = j2k_Container_getHeight(impl->container, error); + tileWidth = j2k_Container_getTileWidth(impl->container, error); + tileHeight = j2k_Container_getTileHeight(impl->container, error); + nComponents = j2k_Container_getNumComponents(impl->container, error); + nBytes = (j2k_Container_getPrecision(impl->container, error) - 1) / 8 + 1; + tileIndex = tileY * xTiles + tileX; + + memset(error->message, 0, NRT_MAX_EMESSAGE); + if(!opj_set_error_handler(impl->codec, + OpenJPEG_errorHandler, + error)) + { + nrt_Error_init(error, "Unable to set OpenJPEG error handler", NRT_CTXT, + NRT_ERR_UNK); + goto CATCH_ERROR; + } + + /* Check for edge case where we may have partial tile */ + thisTileWidth = tileWidth; + thisTileHeight = tileHeight; + if (tileX == xTiles - 1 && width % tileWidth != 0) + thisTileWidth = width % tileWidth; + if (tileY == yTiles - 1 && height % tileHeight != 0) + thisTileHeight = height % tileHeight; + + thisTileSize = thisTileWidth * thisTileHeight * nComponents * nBytes; + if(thisTileSize != tileSize) + tileSize = thisTileSize; + + if(thisTileWidth < tileWidth) + { + /* TODO: The current approach below only works for single band + * imagery. For RGB data, I believe it is stored as all + * red, then all green, then all blue, so we would need + * a temp buffer rather than reusing the current buffer. + */ + if (nComponents != 1) + { + nrt_Error_init( + error, + "Partial tile width not implemented for multi-band", + NRT_CTXT, NRT_ERR_UNK); + goto CATCH_ERROR; + } + + /* We have a tile that is wider than it "should" be + * Need to create smaller buffer to pass to write function + */ + { + OPJ_UINT32 ii; + size_t srcOffset = 0; + size_t destOffset = 0; + const size_t srcStride = tileWidth * nBytes; + const size_t destStride = thisTileWidth * nBytes; + + newTileBuf = (nrt_Uint8*) J2K_MALLOC(thisTileSize); + if(!newTileBuf) + { + nrt_Error_init(error, NRT_STRERROR(NRT_ERRNO), NRT_CTXT, NRT_ERR_MEMORY); + goto CATCH_ERROR; + } + + for(ii = 0; ii < thisTileHeight; ++ii, srcOffset += srcStride, + destOffset += destStride) + memcpy(newTileBuf + destOffset, buf + srcOffset, destStride); + + buf = newTileBuf; + } + } + + if (!opj_write_tile(impl->codec, + tileIndex, + (OPJ_BYTE* )buf, + tileSize, + impl->stream)) + { + nrt_Error ioError; + const nrt_Off currentPos = nrt_IOInterface_tell(impl->compressed, &ioError); + const nrt_Off ioSize = nrt_IOInterface_getSize(impl->compressed, &ioError); + if (NRT_IO_SUCCESS(currentPos) && + NRT_IO_SUCCESS(ioSize) && + currentPos + OPENJPEG_STREAM_SIZE >= ioSize) + { + /* The write failed because implStreamWrite() failed because + * nrt_IOInterface_write() failed because we didn't have enough + * room left in the buffer that we copy to prior to flushing out + * to disk in OpenJPEGWriter_write(). The buffer is sized to the + * uncompressed image size, so this only occurs if the compressed + * image is actually larger than the uncompressed size. + * TODO: Handle resizing the buffer on the fly when this occurs + * inside implStreamWrite(). Long-term if we're able to thread + * per tile, we won't have to reallocate nearly as much. + */ + nrt_Error_init(error, + "Error writing tile: Compressed image is larger " + "than uncompressed image", + NRT_CTXT, + NRT_ERR_INVALID_OBJECT); + } + + /*nrt_Error_init(error, "Error writing tile", NRT_CTXT, + NRT_ERR_INVALID_OBJECT);*/ + goto CATCH_ERROR; + } + + goto CLEANUP; + + CATCH_ERROR: + { + rc = NRT_FAILURE; + } + + CLEANUP: + { + if(newTileBuf) + J2K_FREE(newTileBuf); + } + + return rc; +} + +J2KPRIV( NRT_BOOL) +OpenJPEGWriter_write(J2K_USER_DATA *data, nrt_IOInterface *io, nrt_Error *error) +{ + OpenJPEGWriterImpl *impl = (OpenJPEGWriterImpl*) data; + NRT_BOOL rc = NRT_SUCCESS; + size_t compressedSize; + + memset(error->message, 0, NRT_MAX_EMESSAGE); + if(!opj_set_error_handler(impl->codec, + OpenJPEG_errorHandler, + error)) + { + nrt_Error_init(error, "Unable to set OpenJPEG error handler", NRT_CTXT, + NRT_ERR_UNK); + goto CATCH_ERROR; + } + + if (!opj_end_compress(impl->codec, impl->stream)) + { + /*nrt_Error_init(error, "Error ending compression", NRT_CTXT, + NRT_ERR_INVALID_OBJECT);*/ + goto CATCH_ERROR; + } + + /* just copy/write the compressed data to the output IO */ + compressedSize = (size_t)nrt_IOInterface_tell(impl->compressed, error); + if (!nrt_IOInterface_write(io, impl->compressedBuf, compressedSize, error)) + { + nrt_Error_init(error, "Error writing data", NRT_CTXT, + NRT_ERR_INVALID_OBJECT); + goto CATCH_ERROR; + } + + goto CLEANUP; + + CATCH_ERROR: + { + rc = NRT_FAILURE; + } + + CLEANUP: + { + } + + return rc; +} + +J2KPRIV( j2k_Container*) +OpenJPEGWriter_getContainer(J2K_USER_DATA *data, nrt_Error *error) +{ + OpenJPEGWriterImpl *impl = (OpenJPEGWriterImpl*) data; + return impl->container; +} + +J2KPRIV(void) +OpenJPEGWriter_destruct(J2K_USER_DATA * data) +{ + if (data) + { + OpenJPEGWriterImpl* const impl = (OpenJPEGWriterImpl*) data; + OpenJPEG_cleanup(&impl->stream, &impl->codec, &impl->image); + nrt_IOInterface_destruct(&impl->compressed); + J2K_FREE(data); + } +} + +/******************************************************************************/ +/******************************************************************************/ +/* PUBLIC FUNCTIONS */ +/******************************************************************************/ +/******************************************************************************/ + +J2KAPI(j2k_Reader*) j2k_Reader_open(const char *fname, nrt_Error *error) +{ + j2k_Reader *reader = NULL; + nrt_IOInterface *io = NULL; + + if (!fname) + { + nrt_Error_init(error, "NULL filename", NRT_CTXT, + NRT_ERR_INVALID_OBJECT); + goto CATCH_ERROR; + } + + if (!(io = nrt_IOHandleAdapter_open(fname, NRT_ACCESS_READONLY, + NRT_OPEN_EXISTING, error))) + goto CATCH_ERROR; + + if (!(reader = j2k_Reader_openIO(io, error))) + goto CATCH_ERROR; + + ((OpenJPEGReaderImpl*) reader->data)->ownIO = 1; + + return reader; + + CATCH_ERROR: + { + if (io) + nrt_IOInterface_destruct(&io); + if (reader) + j2k_Reader_destruct(&reader); + return NULL; + } +} + +J2KAPI(j2k_Reader*) j2k_Reader_openIO(nrt_IOInterface *io, nrt_Error *error) +{ + OpenJPEGReaderImpl *impl = NULL; + j2k_Reader *reader = NULL; + + /* create the Reader interface */ + impl = (OpenJPEGReaderImpl *) J2K_MALLOC(sizeof(OpenJPEGReaderImpl)); + if (!impl) + { + nrt_Error_init(error, NRT_STRERROR(NRT_ERRNO), NRT_CTXT, NRT_ERR_MEMORY); + goto CATCH_ERROR; + } + memset(impl, 0, sizeof(OpenJPEGReaderImpl)); + + reader = (j2k_Reader *) J2K_MALLOC(sizeof(j2k_Reader)); + if (!reader) + { + nrt_Error_init(error, NRT_STRERROR(NRT_ERRNO), NRT_CTXT, NRT_ERR_MEMORY); + goto CATCH_ERROR; + } + memset(reader, 0, sizeof(j2k_Reader)); + reader->data = impl; + reader->iface = &ReaderInterface; + + /* initialize the interfaces */ + impl->io = io; + impl->ioOffset = nrt_IOInterface_tell(io, error); + + if (!OpenJPEG_readHeader(impl, error)) + { + goto CATCH_ERROR; + } + + return reader; + + CATCH_ERROR: + { + if (reader) + { + j2k_Reader_destruct(&reader); + } + else if (impl) + { + OpenJPEGReader_destruct((J2K_USER_DATA*) impl); + } + return NULL; + } +} + +J2KAPI(j2k_Writer*) j2k_Writer_construct(j2k_Container *container, + j2k_WriterOptions *writerOps, + nrt_Error *error) +{ + j2k_Writer *writer = NULL; + OpenJPEGWriterImpl *impl = NULL; + + writer = (j2k_Writer*) J2K_MALLOC(sizeof(j2k_Container)); + if (!writer) + { + nrt_Error_init(error, NRT_STRERROR(NRT_ERRNO), NRT_CTXT, NRT_ERR_MEMORY); + goto CATCH_ERROR; + } + memset(writer, 0, sizeof(j2k_Writer)); + + /* create the Writer interface */ + impl = (OpenJPEGWriterImpl *) J2K_MALLOC(sizeof(OpenJPEGWriterImpl)); + if (!impl) + { + nrt_Error_init(error, NRT_STRERROR(NRT_ERRNO), NRT_CTXT, NRT_ERR_MEMORY); + goto CATCH_ERROR; + } + memset(impl, 0, sizeof(OpenJPEGWriterImpl)); + impl->container = container; + + if (!(OpenJPEG_initImage(impl, writerOps, error))) + { + goto CATCH_ERROR; + } + + writer->data = impl; + writer->iface = &WriterInterface; + + return writer; + + CATCH_ERROR: + { + if (writer) + { + j2k_Writer_destruct(&writer); + } + return NULL; + } +} + +#endif diff --git a/modules/c/j2k/source/Reader.c b/modules/c/j2k/source/Reader.c new file mode 100644 index 000000000..e06d235ae --- /dev/null +++ b/modules/c/j2k/source/Reader.c @@ -0,0 +1,63 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "j2k/Reader.h" + +J2KAPI(NRT_BOOL) j2k_Reader_canReadTiles(j2k_Reader *reader, nrt_Error *error) +{ + if (reader->iface->canReadTiles) + return reader->iface->canReadTiles(reader->data, error); + /* otherwise, no */ + return NRT_FAILURE; +} + +J2KAPI(nrt_Uint64) j2k_Reader_readTile(j2k_Reader *reader, + nrt_Uint32 tileX, nrt_Uint32 tileY, + nrt_Uint8 **buf, nrt_Error *error) +{ + return reader->iface->readTile(reader->data, tileX, tileY, buf, error); +} + +J2KAPI(nrt_Uint64) j2k_Reader_readRegion(j2k_Reader *reader, + nrt_Uint32 x0, nrt_Uint32 y0, nrt_Uint32 x1, nrt_Uint32 y1, + nrt_Uint8 **buf, nrt_Error *error) +{ + return reader->iface->readRegion(reader->data, x0, y0, x1, y1, buf, error); +} + +J2KAPI(j2k_Container*) j2k_Reader_getContainer(j2k_Reader *reader, + nrt_Error *error) +{ + return reader->iface->getContainer(reader->data, error); +} + +J2KAPI(void) j2k_Reader_destruct(j2k_Reader **reader) +{ + if (*reader) + { + if ((*reader)->iface && (*reader)->data) + (*reader)->iface->destruct((*reader)->data); + J2K_FREE(*reader); + *reader = NULL; + } +} + diff --git a/modules/c/j2k/source/SimpleComponentImpl.c b/modules/c/j2k/source/SimpleComponentImpl.c new file mode 100644 index 000000000..c004cdcbf --- /dev/null +++ b/modules/c/j2k/source/SimpleComponentImpl.c @@ -0,0 +1,178 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "j2k/Component.h" + + +typedef struct _ComponentImpl +{ + nrt_Uint32 width; + nrt_Uint32 height; + nrt_Uint32 precision; + NRT_BOOL isSigned; + nrt_Int32 x0; + nrt_Int32 y0; + nrt_Uint32 xSeparation; + nrt_Uint32 ySeparation; + +} ComponentImpl; + +J2KPRIV( nrt_Uint32) Component_getWidth(J2K_USER_DATA *, nrt_Error *); +J2KPRIV( nrt_Uint32) Component_getHeight(J2K_USER_DATA *, nrt_Error *); +J2KPRIV( nrt_Uint32) Component_getPrecision(J2K_USER_DATA *, nrt_Error *); +J2KPRIV( J2K_BOOL) Component_isSigned(J2K_USER_DATA *, nrt_Error *); +J2KPRIV( nrt_Int32) Component_getOffsetX(J2K_USER_DATA *, nrt_Error *); +J2KPRIV( nrt_Int32) Component_getOffsetY(J2K_USER_DATA *, nrt_Error *); +J2KPRIV( nrt_Uint32) Component_getSeparationX(J2K_USER_DATA *, nrt_Error *); +J2KPRIV( nrt_Uint32) Component_getSeparationY(J2K_USER_DATA *, nrt_Error *); +J2KPRIV(void) Component_destruct(J2K_USER_DATA *); + +static j2k_IComponent ComponentInterface = { &Component_getWidth, + &Component_getHeight, + &Component_getPrecision, + &Component_isSigned, + &Component_getOffsetX, + &Component_getOffsetY, + &Component_getSeparationX, + &Component_getSeparationY, + &Component_destruct}; + +J2KPRIV( nrt_Uint32) +Component_getWidth(J2K_USER_DATA *data, nrt_Error *error) +{ + ComponentImpl *impl = (ComponentImpl*) data; + return impl->width; +} + +J2KPRIV( nrt_Uint32) +Component_getHeight(J2K_USER_DATA *data, nrt_Error *error) +{ + ComponentImpl *impl = (ComponentImpl*) data; + return impl->height; +} + +J2KPRIV( nrt_Uint32) +Component_getPrecision(J2K_USER_DATA *data, nrt_Error *error) +{ + ComponentImpl *impl = (ComponentImpl*) data; + return impl->precision; +} + +J2KPRIV( NRT_BOOL) +Component_isSigned(J2K_USER_DATA *data, nrt_Error *error) +{ + ComponentImpl *impl = (ComponentImpl*) data; + return impl->isSigned; +} + +J2KPRIV( nrt_Int32) +Component_getOffsetX(J2K_USER_DATA *data, nrt_Error *error) +{ + ComponentImpl *impl = (ComponentImpl*) data; + return impl->x0; +} + +J2KPRIV( nrt_Int32) +Component_getOffsetY(J2K_USER_DATA *data, nrt_Error *error) +{ + ComponentImpl *impl = (ComponentImpl*) data; + return impl->y0; +} + +J2KPRIV( nrt_Uint32) +Component_getSeparationX(J2K_USER_DATA *data, nrt_Error *error) +{ + ComponentImpl *impl = (ComponentImpl*) data; + return impl->xSeparation; +} + +J2KPRIV( nrt_Uint32) +Component_getSeparationY(J2K_USER_DATA *data, nrt_Error *error) +{ + ComponentImpl *impl = (ComponentImpl*) data; + return impl->ySeparation; +} + +J2KPRIV(void) +Component_destruct(J2K_USER_DATA * data) +{ + if (data) + { + ComponentImpl *impl = (ComponentImpl*) data; + J2K_FREE(data); + } +} + + +J2KAPI(j2k_Component*) j2k_Component_construct(nrt_Uint32 width, + nrt_Uint32 height, + nrt_Uint32 precision, + NRT_BOOL isSigned, + nrt_Uint32 offsetX, + nrt_Uint32 offsetY, + nrt_Uint32 separationX, + nrt_Uint32 separationY, + nrt_Error *error) +{ + j2k_Component *component = NULL; + ComponentImpl *impl = NULL; + + component = (j2k_Component*) J2K_MALLOC(sizeof(j2k_Component)); + if (!component) + { + nrt_Error_init(error, NRT_STRERROR(NRT_ERRNO), NRT_CTXT, NRT_ERR_MEMORY); + goto CATCH_ERROR; + } + memset(component, 0, sizeof(j2k_Component)); + + /* create the Component interface */ + impl = (ComponentImpl *) J2K_MALLOC(sizeof(ComponentImpl)); + if (!impl) + { + nrt_Error_init(error, NRT_STRERROR(NRT_ERRNO), NRT_CTXT, NRT_ERR_MEMORY); + goto CATCH_ERROR; + } + memset(impl, 0, sizeof(ComponentImpl)); + component->data = impl; + component->iface = &ComponentInterface; + + impl->width = width; + impl->height = height; + impl->precision = precision; + impl->isSigned = isSigned; + impl->x0 = offsetX; + impl->y0 = offsetY; + impl->xSeparation = separationX; + impl->ySeparation = separationY; + + return component; + + CATCH_ERROR: + { + if (component) + { + j2k_Component_destruct(&component); + } + return NULL; + } +} + diff --git a/modules/c/j2k/source/SimpleContainerImpl.c b/modules/c/j2k/source/SimpleContainerImpl.c new file mode 100644 index 000000000..144d0a21f --- /dev/null +++ b/modules/c/j2k/source/SimpleContainerImpl.c @@ -0,0 +1,205 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "j2k/Container.h" + + +typedef struct _ContainerImpl +{ + nrt_Uint32 gridWidth; + nrt_Uint32 gridHeight; + nrt_Uint32 nComponents; + j2k_Component **components; + nrt_Uint32 xTiles; + nrt_Uint32 yTiles; + nrt_Uint32 tileWidth; + nrt_Uint32 tileHeight; + int imageType; +} ContainerImpl; + + +J2KPRIV( nrt_Uint32) Container_getGridWidth(J2K_USER_DATA *, nrt_Error *); +J2KPRIV( nrt_Uint32) Container_getGridHeight(J2K_USER_DATA *, nrt_Error *); +J2KPRIV( nrt_Uint32) Container_getNumComponents(J2K_USER_DATA *, nrt_Error *); +J2KPRIV( j2k_Component*)Container_getComponent(J2K_USER_DATA *, nrt_Uint32, nrt_Error *); +J2KPRIV( nrt_Uint32) Container_getTilesX(J2K_USER_DATA *, nrt_Error *); +J2KPRIV( nrt_Uint32) Container_getTilesY(J2K_USER_DATA *, nrt_Error *); +J2KPRIV( nrt_Uint32) Container_getTileWidth(J2K_USER_DATA *, nrt_Error *); +J2KPRIV( nrt_Uint32) Container_getTileHeight(J2K_USER_DATA *, nrt_Error *); +J2KPRIV( int) Container_getImageType(J2K_USER_DATA *, nrt_Error *); +J2KPRIV(void) Container_destruct(J2K_USER_DATA *); + +static j2k_IContainer ContainerInterface = { &Container_getGridWidth, + &Container_getGridHeight, + &Container_getNumComponents, + &Container_getComponent, + &Container_getTilesX, + &Container_getTilesY, + &Container_getTileWidth, + &Container_getTileHeight, + &Container_getImageType, + &Container_destruct}; + +J2KPRIV( nrt_Uint32) +Container_getGridWidth(J2K_USER_DATA *data, nrt_Error *error) +{ + ContainerImpl *impl = (ContainerImpl*) data; + return impl->gridWidth; +} + +J2KPRIV( nrt_Uint32) +Container_getGridHeight(J2K_USER_DATA *data, nrt_Error *error) +{ + ContainerImpl *impl = (ContainerImpl*) data; + return impl->gridHeight; +} + +J2KPRIV( nrt_Uint32) +Container_getNumComponents(J2K_USER_DATA *data, nrt_Error *error) +{ + ContainerImpl *impl = (ContainerImpl*) data; + return impl->nComponents; +} + +J2KPRIV( j2k_Component*) +Container_getComponent(J2K_USER_DATA *data, nrt_Uint32 idx, nrt_Error *error) +{ + ContainerImpl *impl = (ContainerImpl*) data; + if (idx >= impl->nComponents) + { + nrt_Error_init(error, "Invalid component index", + NRT_CTXT, NRT_ERR_INVALID_OBJECT); + return NULL; + } + return impl->components[idx]; +} + +J2KPRIV( nrt_Uint32) +Container_getTilesX(J2K_USER_DATA *data, nrt_Error *error) +{ + ContainerImpl *impl = (ContainerImpl*) data; + return impl->xTiles; +} + +J2KPRIV( nrt_Uint32) +Container_getTilesY(J2K_USER_DATA *data, nrt_Error *error) +{ + ContainerImpl *impl = (ContainerImpl*) data; + return impl->yTiles; +} + +J2KPRIV( nrt_Uint32) +Container_getTileWidth(J2K_USER_DATA *data, nrt_Error *error) +{ + ContainerImpl *impl = (ContainerImpl*) data; + return impl->tileWidth; +} + +J2KPRIV( nrt_Uint32) +Container_getTileHeight(J2K_USER_DATA *data, nrt_Error *error) +{ + ContainerImpl *impl = (ContainerImpl*) data; + return impl->tileHeight; +} + +J2KPRIV( int) +Container_getImageType(J2K_USER_DATA *data, nrt_Error *error) +{ + ContainerImpl *impl = (ContainerImpl*) data; + return impl->imageType; +} + +J2KPRIV(void) +Container_destruct(J2K_USER_DATA * data) +{ + if (data) + { + ContainerImpl *impl = (ContainerImpl*) data; + if (impl->components) + { + nrt_Uint32 i = 0; + for(; i < impl->nComponents; ++i) + { + j2k_Component *c = impl->components[i]; + if (c) + j2k_Component_destruct(&c); + } + J2K_FREE(impl->components); + impl->components = NULL; + } + J2K_FREE(data); + } +} + + +J2KAPI(j2k_Container*) j2k_Container_construct(nrt_Uint32 gridWidth, + nrt_Uint32 gridHeight, + nrt_Uint32 numComponents, + j2k_Component** components, + nrt_Uint32 tileWidth, + nrt_Uint32 tileHeight, + int imageType, + nrt_Error *error) +{ + j2k_Container *container = NULL; + ContainerImpl *impl = NULL; + + container = (j2k_Container*) J2K_MALLOC(sizeof(j2k_Container)); + if (!container) + { + nrt_Error_init(error, NRT_STRERROR(NRT_ERRNO), NRT_CTXT, NRT_ERR_MEMORY); + goto CATCH_ERROR; + } + memset(container, 0, sizeof(j2k_Container)); + + /* create the Container interface */ + impl = (ContainerImpl *) J2K_MALLOC(sizeof(ContainerImpl)); + if (!impl) + { + nrt_Error_init(error, NRT_STRERROR(NRT_ERRNO), NRT_CTXT, NRT_ERR_MEMORY); + goto CATCH_ERROR; + } + memset(impl, 0, sizeof(ContainerImpl)); + container->data = impl; + container->iface = &ContainerInterface; + + impl->gridWidth = gridWidth; + impl->gridHeight = gridHeight; + impl->nComponents = numComponents; + impl->components = components; + impl->tileWidth = tileWidth; + impl->tileHeight = tileHeight; + impl->xTiles = gridWidth / tileWidth + (gridWidth % tileWidth == 0 ? 0 : 1); + impl->yTiles = gridHeight / tileHeight + (gridHeight % tileHeight == 0 ? 0 : 1); + impl->imageType = imageType; + + return container; + + CATCH_ERROR: + { + if (container) + { + j2k_Container_destruct(&container); + } + return NULL; + } +} diff --git a/modules/c/j2k/source/Writer.c b/modules/c/j2k/source/Writer.c new file mode 100644 index 000000000..94ac2b9f8 --- /dev/null +++ b/modules/c/j2k/source/Writer.c @@ -0,0 +1,83 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "j2k/Writer.h" +#include "nitf/WriterOptions.h" + +J2KAPI(NRT_BOOL) j2k_Writer_setOptions(j2k_WriterOptions* options, + nrt_HashTable* userOptions, + nrt_Error* error) +{ + nrt_Pair* compressionRatio; + nrt_Pair* numResolutions; + if(options && userOptions) + { + compressionRatio = nrt_HashTable_find(userOptions, C8_COMPRESSION_RATIO_KEY); + numResolutions = nrt_HashTable_find(userOptions, C8_NUM_RESOLUTIONS_KEY); + + if(compressionRatio) + { + options->compressionRatio = *((double*)compressionRatio->data); + } + if(numResolutions) + { + options->numResolutions = *((nrt_Uint32*)numResolutions->data); + } + } + + return NRT_SUCCESS; +} + +J2KAPI(NRT_BOOL) j2k_Writer_setTile(j2k_Writer *writer, + nrt_Uint32 tileX, + nrt_Uint32 tileY, + const nrt_Uint8 *buf, + nrt_Uint32 bufSize, + nrt_Error *error) +{ + return writer->iface->setTile(writer->data, tileX, tileY, buf, bufSize, error); +} + +J2KAPI(NRT_BOOL) j2k_Writer_write(j2k_Writer *writer, + nrt_IOInterface *io, + nrt_Error *error) +{ + return writer->iface->write(writer->data, io, error); +} + +J2KAPI(j2k_Container*) j2k_Writer_getContainer(j2k_Writer *writer, + nrt_Error *error) +{ + return writer->iface->getContainer(writer->data, error); +} + +J2KAPI(void) j2k_Writer_destruct(j2k_Writer **writer) +{ + if (*writer) + { + if ((*writer)->iface && (*writer)->data) + (*writer)->iface->destruct((*writer)->data); + J2K_FREE(*writer); + *writer = NULL; + } +} + diff --git a/modules/c/j2k/tests/test_j2k_create.c b/modules/c/j2k/tests/test_j2k_create.c new file mode 100644 index 000000000..ca5fb2765 --- /dev/null +++ b/modules/c/j2k/tests/test_j2k_create.c @@ -0,0 +1,172 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include +#include + +J2K_BOOL readFile(const char* filename, char **buf, nrt_Uint64 *bufSize, + nrt_Error *error) +{ + J2K_BOOL rc = J2K_TRUE; + nrt_IOInterface *io = NULL; + + if (!(io = nrt_IOHandleAdapter_open(filename, NRT_ACCESS_READONLY, + NRT_OPEN_EXISTING, error))) + goto CATCH_ERROR; + + *bufSize = nrt_IOInterface_getSize(io, error); + if (!(*buf = (char*)J2K_MALLOC(*bufSize))) + { + nrt_Error_init(error, NRT_STRERROR(NRT_ERRNO), NRT_CTXT, NRT_ERR_MEMORY); + goto CATCH_ERROR; + } + + if (!nrt_IOInterface_read(io, *buf, *bufSize, error)) + { + goto CATCH_ERROR; + } + + goto CLEANUP; + + CATCH_ERROR: + { + rc = J2K_FALSE; + if (*buf) + J2K_FREE(*buf); + *buf = NULL; + } + CLEANUP: + { + if (io) + nrt_IOInterface_destruct(&io); + } + return rc; +} + + + +int main(int argc, char **argv) +{ + int rc = 0; + int argIt = 0; + char *inName = NULL, *outName = NULL; + nrt_Error error; + j2k_Component *component = NULL; + j2k_Container *container = NULL; + j2k_Writer *writer = NULL; + j2k_WriterOptions options; + char *buf = NULL; + nrt_Uint64 bufSize; + nrt_IOInterface *outIO = NULL; + nrt_Uint32 width, height, precision, tileWidth, tileHeight; + + for (argIt = 1; argIt < argc; ++argIt) + { + if (!inName) + { + inName = argv[argIt]; + } + else if (!outName) + { + outName = argv[argIt]; + } + } + + /* hardcoded for now... */ + width = 128; + height = 128; + precision = 8; + tileWidth = width; + tileHeight = height; + + if (!inName || !outName) + { + nrt_Error_initf(&error, NRT_CTXT, NRT_ERR_INVALID_OBJECT, + "Usage: %s ", argv[0]); + goto CATCH_ERROR; + } + + if (!(component = j2k_Component_construct(width, height, precision, + 0, 0, 0, 1, 1, &error))) + { + goto CATCH_ERROR; + } + + if (!(container = j2k_Container_construct(width, + height, + 1, + &component, + tileWidth, + tileHeight, + J2K_TYPE_MONO, + &error))) + { + goto CATCH_ERROR; + } + + memset(&options, 0, sizeof(j2k_WriterOptions)); + /* TODO set some options here */ + + if (!(writer = j2k_Writer_construct(container, &options, &error))) + { + goto CATCH_ERROR; + } + + if (!readFile(inName, &buf, &bufSize, &error)) + { + goto CATCH_ERROR; + } + + if (!j2k_Writer_setTile(writer, 0, 0, (nrt_Uint8*)buf, + (nrt_Uint32)bufSize, &error)) + { + goto CATCH_ERROR; + } + + if (!(outIO = nrt_IOHandleAdapter_open(outName, NRT_ACCESS_WRITEONLY, + NRT_CREATE, &error))) + goto CATCH_ERROR; + + if (!j2k_Writer_write(writer, outIO, &error)) + goto CATCH_ERROR; + + goto CLEANUP; + + CATCH_ERROR: + { + nrt_Error_print(&error, stdout, "Exiting..."); + rc = 1; + } + CLEANUP: + { + if (container) + j2k_Container_destruct(&container); + if (writer) + j2k_Writer_destruct(&writer); + if (buf) + J2K_FREE(buf); + if (outIO) + nrt_IOInterface_destruct(&outIO); + } + return rc; + +} diff --git a/modules/c/j2k/tests/test_j2k_header.c b/modules/c/j2k/tests/test_j2k_header.c new file mode 100644 index 000000000..2a4c08bde --- /dev/null +++ b/modules/c/j2k/tests/test_j2k_header.c @@ -0,0 +1,96 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include +#include + +int main(int argc, char **argv) +{ + int rc = 0; + int argIt; + nrt_Uint32 cmpIt, nComponents; + nrt_Error error; + j2k_Container *container = NULL; + j2k_Reader *reader = NULL; + char *fname = NULL; + + for (argIt = 1; argIt < argc; ++argIt) + { + if (!fname) + { + fname = argv[argIt]; + } + } + + if (!fname) + { + nrt_Error_init(&error, "Usage: [options] ", NRT_CTXT, + NRT_ERR_INVALID_OBJECT); + goto CATCH_ERROR; + } + + if (!(reader = j2k_Reader_open(fname, &error))) + goto CATCH_ERROR; + + if (!(container = j2k_Reader_getContainer(reader, &error))) + goto CATCH_ERROR; + + printf("grid width:\t%d\n", j2k_Container_getGridWidth(container, &error)); + printf("grid height:\t%d\n", j2k_Container_getGridHeight(container, &error)); + printf("tile width:\t%d\n", j2k_Container_getTileWidth(container, &error)); + printf("tile height:\t%d\n", j2k_Container_getTileHeight(container, &error)); + printf("x tiles:\t%d\n", j2k_Container_getTilesX(container, &error)); + printf("y tiles:\t%d\n", j2k_Container_getTilesY(container, &error)); + printf("image type:\t%d\n", j2k_Container_getImageType(container, &error)); + + nComponents = j2k_Container_getNumComponents(container, &error); + printf("components:\t%d\n", nComponents); + + for(cmpIt = 0; cmpIt < nComponents; ++cmpIt) + { + j2k_Component* c = j2k_Container_getComponent(container, cmpIt, &error); + printf("===component %d===\n", (cmpIt + 1)); + printf("width:\t\t%d\n", j2k_Component_getWidth(c, &error)); + printf("height:\t\t%d\n", j2k_Component_getHeight(c, &error)); + printf("precision:\t%d\n", j2k_Component_getPrecision(c, &error)); + printf("x0:\t\t%d\n", j2k_Component_getOffsetX(c, &error)); + printf("y0:\t\t%d\n", j2k_Component_getOffsetY(c, &error)); + printf("x separation:\t%d\n", j2k_Component_getSeparationX(c, &error)); + printf("y separation:\t%d\n", j2k_Component_getSeparationY(c, &error)); + printf("signed:\t\t%d\n", j2k_Component_isSigned(c, &error)); + } + + goto CLEANUP; + + CATCH_ERROR: + { + nrt_Error_print(&error, stdout, "Exiting..."); + rc = 1; + } + CLEANUP: + { + if (reader) + j2k_Reader_destruct(&reader); + } + return rc; + +} diff --git a/modules/c/j2k/tests/test_j2k_nitf.c b/modules/c/j2k/tests/test_j2k_nitf.c new file mode 100644 index 000000000..f7cd45f0d --- /dev/null +++ b/modules/c/j2k/tests/test_j2k_nitf.c @@ -0,0 +1,212 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include +#include +#include + +NRT_BOOL writeFile(nrt_Uint32 x0, nrt_Uint32 y0, + nrt_Uint32 x1, nrt_Uint32 y1, nrt_Uint8 *buf, + nrt_Uint64 bufSize, const char* prefix, nrt_Error *error) +{ + NRT_BOOL rc = NRT_SUCCESS; + char filename[NRT_MAX_PATH]; + nrt_IOHandle outHandle; + + NRT_SNPRINTF(filename, NRT_MAX_PATH, "%s-raw-%d_%d__%d_%d.out", prefix, x0, + y0, x1, y1); + outHandle = nrt_IOHandle_create(filename, NRT_ACCESS_WRITEONLY, NRT_CREATE, + error); + if (NRT_INVALID_HANDLE(outHandle)) + { + goto CATCH_ERROR; + } + if (!nrt_IOHandle_write(outHandle, (const char *) buf, bufSize, error)) + { + goto CATCH_ERROR; + } + printf("Wrote file: %s\n", filename); + + goto CLEANUP; + + CATCH_ERROR: + { + rc = NRT_FAILURE; + } + CLEANUP: + { + if (!NRT_INVALID_HANDLE(outHandle)) + nrt_IOHandle_close(outHandle); + } + return rc; +} + +int main(int argc, char **argv) +{ + int rc = 0; + int argIt = 0, i = 0, num = 0, dump = 0; + char *fname = NULL; + nrt_Error error; + nrt_IOInterface *io = NULL; + nitf_Reader *reader = NULL; + nitf_Record *record = NULL; + nrt_Uint8 *buf = NULL; + + for (argIt = 1; argIt < argc; ++argIt) + { + if (strcmp(argv[argIt], "--dump") == 0) + dump = 1; + else if (!fname) + { + fname = argv[argIt]; + } + } + + if (!fname) + { + nrt_Error_init(&error, "Usage: [--x0 --y0 --x1 --y1] ", + NRT_CTXT, NRT_ERR_INVALID_OBJECT); + goto CATCH_ERROR; + } + + if (nitf_Reader_getNITFVersion(fname) == NITF_VER_UNKNOWN) + { + nrt_Error_init(&error, "This file does not appear to be a valid NITF", + NRT_CTXT, NRT_ERR_INVALID_OBJECT); + goto CATCH_ERROR; + } + + if (!(io = nrt_IOHandleAdapter_open(fname, NRT_ACCESS_READONLY, NRT_OPEN_EXISTING, + &error))) + goto CATCH_ERROR; + + if (!(reader = nitf_Reader_construct(&error))) + goto CATCH_ERROR; + + if (!(record = nitf_Reader_readIO(reader, io, &error))) + goto CATCH_ERROR; + + num = nitf_Record_getNumImages(record, &error); + if (num > 0) + { + nitf_ListIterator iter = nitf_List_begin(record->images); + nitf_ListIterator end = nitf_List_end(record->images); + + for (i = 0; nitf_ListIterator_notEqualTo(&iter, &end); ++i) + { + nitf_ImageSegment *segment = + (nitf_ImageSegment *) nitf_ListIterator_get(&iter); + nitf_ImageSubheader *subheader = segment->subheader; + + if (strcmp(subheader->imageCompression->raw, "C8") == 0) + { + j2k_Reader *j2kReader = NULL; + j2k_Container *container = NULL; + nrt_Uint32 cmpIt, nComponents; + printf("Image %d contains J2K compressed data\n", (i + 1)); + printf("Offset: %d\n", segment->imageOffset); + if (!nrt_IOInterface_seek(io, segment->imageOffset, + NRT_SEEK_SET, &error)) + goto CATCH_ERROR; + if (!(j2kReader = j2k_Reader_openIO(io, &error))) + goto CATCH_ERROR; + if (!(container = j2k_Reader_getContainer(j2kReader, &error))) + goto CATCH_ERROR; + + + printf("grid width:\t%d\n", j2k_Container_getGridWidth(container, &error)); + printf("grid height:\t%d\n", j2k_Container_getGridHeight(container, &error)); + printf("tile width:\t%d\n", j2k_Container_getTileWidth(container, &error)); + printf("tile height:\t%d\n", j2k_Container_getTileHeight(container, &error)); + printf("x tiles:\t%d\n", j2k_Container_getTilesX(container, &error)); + printf("y tiles:\t%d\n", j2k_Container_getTilesY(container, &error)); + printf("image type:\t%d\n", j2k_Container_getImageType(container, &error)); + + nComponents = j2k_Container_getNumComponents(container, &error); + printf("components:\t%d\n", nComponents); + + for(cmpIt = 0; cmpIt < nComponents; ++cmpIt) + { + j2k_Component* c = j2k_Container_getComponent(container, cmpIt, &error); + printf("===component %d===\n", (cmpIt + 1)); + printf("width:\t\t%d\n", j2k_Component_getWidth(c, &error)); + printf("height:\t\t%d\n", j2k_Component_getHeight(c, &error)); + printf("precision:\t%d\n", j2k_Component_getPrecision(c, &error)); + printf("x0:\t\t%d\n", j2k_Component_getOffsetX(c, &error)); + printf("y0:\t\t%d\n", j2k_Component_getOffsetY(c, &error)); + printf("x separation:\t%d\n", j2k_Component_getSeparationX(c, &error)); + printf("y separation:\t%d\n", j2k_Component_getSeparationY(c, &error)); + printf("signed:\t\t%d\n", j2k_Component_isSigned(c, &error)); + } + + if (dump) + { + char namePrefix[NRT_MAX_PATH]; + nrt_Uint32 width, height; + nrt_Uint64 bufSize; + if (buf) + { + NRT_FREE(buf); + buf = NULL; + } + width = j2k_Container_getWidth(container, &error); + height = j2k_Container_getWidth(container, &error); + + if ((bufSize = j2k_Reader_readRegion(j2kReader, 0, 0, + width, height, + &buf, &error)) == 0) + { + goto CATCH_ERROR; + } + + NRT_SNPRINTF(namePrefix, NRT_MAX_PATH, "image-%d", (i + 1)); + if (!writeFile(0, 0, width, height, buf, bufSize, + namePrefix, &error)) + { + goto CATCH_ERROR; + } + } + } + + nitf_ListIterator_increment(&iter); + } + } + + goto CLEANUP; + + CATCH_ERROR: + { + nrt_Error_print(&error, stdout, "Exiting..."); + rc = 1; + } + CLEANUP: + { + if (reader) + nitf_Reader_destruct(&reader); + if (record) + nitf_Record_destruct(&record); + if (io) + nrt_IOInterface_destruct(&io); + } + return rc; + +} diff --git a/modules/c/j2k/tests/test_j2k_read_region.c b/modules/c/j2k/tests/test_j2k_read_region.c new file mode 100644 index 000000000..907648415 --- /dev/null +++ b/modules/c/j2k/tests/test_j2k_read_region.c @@ -0,0 +1,151 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include +#include + +NRT_BOOL writeFile(nrt_Uint32 x0, nrt_Uint32 y0, + nrt_Uint32 x1, nrt_Uint32 y1, nrt_Uint8 *buf, + nrt_Uint64 bufSize, nrt_Error *error) +{ + NRT_BOOL rc = NRT_SUCCESS; + char filename[NRT_MAX_PATH]; + nrt_IOHandle outHandle; + + NRT_SNPRINTF(filename, NRT_MAX_PATH, "raw-%d_%d__%d_%d.out", x0, y0, x1, y1); + outHandle = nrt_IOHandle_create(filename, NRT_ACCESS_WRITEONLY, NRT_CREATE, + error); + if (NRT_INVALID_HANDLE(outHandle)) + { + goto CATCH_ERROR; + } + if (!nrt_IOHandle_write(outHandle, (const char *) buf, bufSize, error)) + { + goto CATCH_ERROR; + } + printf("Wrote file: %s\n", filename); + + goto CLEANUP; + + CATCH_ERROR: + { + rc = NRT_FAILURE; + } + CLEANUP: + { + if (!NRT_INVALID_HANDLE(outHandle)) + nrt_IOHandle_close(outHandle); + } + return rc; +} + +int main(int argc, char **argv) +{ + int rc = 0; + int argIt = 0; + char *fname = NULL; + nrt_Error error; + j2k_Reader *reader = NULL; + j2k_Container *container = NULL; + nrt_Uint64 bufSize; + nrt_Uint32 x0 = 0; + nrt_Uint32 y0 = 0; + nrt_Uint32 x1 = 0; + nrt_Uint32 y1 = 0; + nrt_Uint8 *buf = NULL; + + for (argIt = 1; argIt < argc; ++argIt) + { + if (strcmp(argv[argIt], "--x0") == 0) + { + if (argIt >= argc - 1) + goto CATCH_ERROR; + x0 = atoi(argv[++argIt]); + } + else if (strcmp(argv[argIt], "--y0") == 0) + { + if (argIt >= argc - 1) + goto CATCH_ERROR; + y0 = atoi(argv[++argIt]); + } + else if (strcmp(argv[argIt], "--x1") == 0) + { + if (argIt >= argc - 1) + goto CATCH_ERROR; + x1 = atoi(argv[++argIt]); + } + else if (strcmp(argv[argIt], "--y1") == 0) + { + if (argIt >= argc - 1) + goto CATCH_ERROR; + y1 = atoi(argv[++argIt]); + } + else if (!fname) + { + fname = argv[argIt]; + } + } + + if (!fname) + { + printf("Usage: %s [--x0 --y0 --x1 --y1] \n", argv[0]); + goto CATCH_ERROR; + } + + if (!(reader = j2k_Reader_open(fname, &error))) + goto CATCH_ERROR; + if (!(container = j2k_Reader_getContainer(reader, &error))) + goto CATCH_ERROR; + + if (x1 == 0) + x1 = j2k_Container_getWidth(container, &error); + if (y1 == 0) + y1 = j2k_Container_getHeight(container, &error); + + if ((bufSize = j2k_Reader_readRegion(reader, x0, y0, x1, y1, &buf, + &error)) == 0) + { + goto CATCH_ERROR; + } + + if (!writeFile(x0, y0, x1, y1, buf, bufSize, &error)) + { + goto CATCH_ERROR; + } + + goto CLEANUP; + + CATCH_ERROR: + { + nrt_Error_print(&error, stdout, "Exiting..."); + rc = 1; + } + CLEANUP: + { + if (reader) + j2k_Reader_destruct(&reader); + if (buf) + NRT_FREE(buf); + } + return rc; + +} diff --git a/modules/c/j2k/tests/test_j2k_read_tile.c b/modules/c/j2k/tests/test_j2k_read_tile.c new file mode 100644 index 000000000..b58eb4bf1 --- /dev/null +++ b/modules/c/j2k/tests/test_j2k_read_tile.c @@ -0,0 +1,133 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include +#include + +NRT_BOOL writeFile(j2k_Container *container, nrt_Uint32 tileX, + nrt_Uint32 tileY, nrt_Uint8 *buf, nrt_Uint32 bufSize, + nrt_Error *error) +{ + NRT_BOOL rc = NRT_SUCCESS; + char filename[NRT_MAX_PATH]; + nrt_IOHandle outHandle; + + NRT_SNPRINTF(filename, NRT_MAX_PATH, "raw-%d_%d__%dx%d.out", tileX, tileY, + j2k_Container_getTileWidth(container, error), + j2k_Container_getTileHeight(container, error)); + outHandle = nrt_IOHandle_create(filename, NRT_ACCESS_WRITEONLY, NRT_CREATE, + error); + if (NRT_INVALID_HANDLE(outHandle)) + { + goto CATCH_ERROR; + } + if (!nrt_IOHandle_write(outHandle, (const char *) buf, bufSize, error)) + { + goto CATCH_ERROR; + } + printf("Wrote file: %s\n", filename); + + goto CLEANUP; + + CATCH_ERROR: + { + rc = NRT_FAILURE; + } + CLEANUP: + { + if (!NRT_INVALID_HANDLE(outHandle)) + nrt_IOHandle_close(outHandle); + } + return rc; +} + +int main(int argc, char **argv) +{ + int rc = 0; + nrt_Error error; + nrt_IOHandle handle; + j2k_Reader *reader = NULL; + j2k_Container *container = NULL; + int argIt = 0; + char *fname = NULL; + nrt_Uint32 tileX = 0; + nrt_Uint32 tileY = 0; + nrt_Uint32 bufSize; + nrt_Uint8 *buf = NULL; + + for (argIt = 1; argIt < argc; ++argIt) + { + if (strcmp(argv[argIt], "--x") == 0) + { + if (argIt >= argc - 1) + goto CATCH_ERROR; + tileX = atoi(argv[++argIt]); + } + else if (strcmp(argv[argIt], "--y") == 0) + { + if (argIt >= argc - 1) + goto CATCH_ERROR; + tileY = atoi(argv[++argIt]); + } + else if (!fname) + { + fname = argv[argIt]; + } + } + + if (!fname) + { + printf("Usage: %s [--x --y] \n", argv[0]); + goto CATCH_ERROR; + } + + if (!(reader = j2k_Reader_open(fname, &error))) + goto CATCH_ERROR; + if (!(container = j2k_Reader_getContainer(reader, &error))) + goto CATCH_ERROR; + + if ((bufSize = j2k_Reader_readTile(reader, tileX, tileY, &buf, &error)) == 0) + { + goto CATCH_ERROR; + } + + if (!writeFile(container, tileX, tileY, buf, bufSize, &error)) + { + goto CATCH_ERROR; + } + + goto CLEANUP; + + CATCH_ERROR: + { + nrt_Error_print(&error, stdout, "Exiting..."); + rc = 1; + } + CLEANUP: + { + if (reader) + j2k_Reader_destruct(&reader); + if (buf) + NRT_FREE(buf); + } + return rc; +} diff --git a/modules/c/j2k/wscript b/modules/c/j2k/wscript new file mode 100644 index 000000000..75fcb07f0 --- /dev/null +++ b/modules/c/j2k/wscript @@ -0,0 +1,74 @@ +from os.path import join, isdir, exists +from waflib import Options + +APIS = ['external/openjpeg', 'external/jasper'] + +def options(opt): + opt.add_option('--disable-j2k', action='store_false', dest='enable_j2k', default=True, + help='turn off JPEG2000 support') + opt.add_option('--j2k-layer', action='store', dest='j2k_layer', + choices=['openjpeg', 'jasper'], default='openjpeg', metavar='LIB', + help='Specify the JPEG2000 library to link with') + + existingDirs = filter(lambda x: exists(join(opt.path.abspath(), x)), APIS) + opt.recurse(existingDirs) + +def configure(conf): + if Options.options.enable_j2k : + conf.msg('Configuring with J2K layer', Options.options.j2k_layer) + existingDirs = filter(lambda x: exists(join(conf.path.abspath(), x)), APIS) + conf.recurse(existingDirs) + +def build(bld): + env = bld.get_env() + if 'HAVE_J2K' in env : + existingDirs = filter(lambda x: exists(join(bld.path.abspath(), x)), APIS) + bld.recurse(existingDirs + ['shared']) + + if 'MAKE_OPENJPEG' in env : + j2kLayer = 'openjpeg' + elif 'MAKE_JASPER' in env : + j2kLayer = 'jasper' + else : + bld.fatal('Not a supported j2k type') + + j2kSources = ('source/Container.c', + 'source/Component.c', + 'source/JasPerImpl.c', + 'source/OpenJPEGImpl.c', + 'source/Reader.c', + 'source/SimpleComponentImpl.c', + 'source/SimpleContainerImpl.c', + 'source/Writer.c') + + #build the j2k library + lib = bld(features='c cstlib', includes='include', + target='j2k-c', name='j2k-c', + source=j2kSources, + export_includes='include', + env=env.derive(), path=bld.path, + use='nitf-c J2K ' + j2kLayer) + + # install j2k lib + if env['install_libs']: + lib.install_path = env['install_libdir'] + + #j2k-only tests + for t in ['test_j2k_header', 'test_j2k_read_tile', 'test_j2k_read_region', + 'test_j2k_create']: + bld.program_helper(dir='tests', source='%s.c' % t, + use='j2k-c J2K ' + j2kLayer, + name=t, target=t, lang='c', env=env.derive()) + + #j2k/nitf tests + for t in ['test_j2k_nitf']: + bld.program_helper(dir='tests', source='%s.c' % t, + use='nitf-c j2k-c J2K', uselib=j2kLayer, + name=t, target=t, lang='c', env=env.derive()) + +def distclean(context) : + + existingDirs = filter(lambda x: exists(join(context.path.abspath(), x)), APIS) + context.recurse(existingDirs) + + diff --git a/modules/c/nitf/COPYING b/modules/c/nitf/COPYING new file mode 100644 index 000000000..94a9ed024 --- /dev/null +++ b/modules/c/nitf/COPYING @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/modules/c/nitf/COPYING.LESSER b/modules/c/nitf/COPYING.LESSER new file mode 100644 index 000000000..fc8a5de7e --- /dev/null +++ b/modules/c/nitf/COPYING.LESSER @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/modules/c/nitf/Doxyfile b/modules/c/nitf/Doxyfile new file mode 100644 index 000000000..e4195f747 --- /dev/null +++ b/modules/c/nitf/Doxyfile @@ -0,0 +1,1040 @@ +# Doxyfile 1.3-rc3 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# General configuration options +#--------------------------------------------------------------------------- + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = NITF +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = 2.5 + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = doc + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, +# Finnish, French, German, Greek, Hungarian, Italian, Japanese, Japanese-en +# (Japanese with english messages), Korean, Norwegian, Polish, Portuguese, +# Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish and Ukrainian. + +OUTPUT_LANGUAGE = English + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these class will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited +# members of a class in the documentation of that class as if those members were +# ordinary class members. Constructors, destructors and assignment operators of +# the base classes will not be shown. + +INLINE_INHERITED_MEMB = YES + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = NO + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. It is allowed to use relative paths in the argument list. + +STRIP_FROM_PATH = + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower case letters. If set to YES upper case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# users are adviced to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like the Qt-style comments (thus requiring an +# explict @brief command for a brief description. + +JAVADOC_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the DETAILS_AT_TOP tag is set to YES then Doxygen +# will output the detailed description near the top, like JavaDoc. +# If set to NO, the detailed description appears after the member +# documentation. + +DETAILS_AT_TOP = YES + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# reimplements. + +INHERIT_DOCS = YES + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 8 + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consist of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. +# For instance some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = YES + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources +# only. Doxygen will then generate output that is more tailored for Java. +# For instance namespaces will be presented as packages, qualified scopes +# will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp +# *.h++ *.idl *.odl + +FILE_PATTERNS = *.h + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = shared include/nitf/unused include/nitf/old tests build + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or directories +# that are symbolic links (a Unix filesystem feature) are excluded from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. + +EXCLUDE_PATTERNS = *tests/* *.c + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = *.xcpp + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = YES + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. + +INPUT_FILTER = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES (the default) +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = YES + +# If the REFERENCES_RELATION tag is set to YES (the default) +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet + +HTML_STYLESHEET = + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output dir. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non empty doxygen will try to run +# the html help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the Html help documentation and to the tree view. + +TOC_EXPAND = NO + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 4 + +# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be +# generated containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (for instance Mozilla, +# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are +# probably better off using the HTML help feature. + +GENERATE_TREEVIEW = YES + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = NO + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = NO + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimised for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assigments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_XML = NO + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = YES + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_PREDEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. + +PREDEFINED = NITFAPI(X)=X __cplusplus=1 NITF_CXX_GUARD NITF_CXX_ENDGUARD + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = NO + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse the +# parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::addtions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES tag can be used to specify one or more tagfiles. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = nitf.tag + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in Html, RTF and LaTeX) for classes with base or +# super classes. Setting the tag to NO turns the diagrams off. Note that this +# option is superceded by the HAVE_DOT option below. This is only a fallback. It is +# recommended to install and use dot, since it yield more powerful graphs. + +CLASS_DIAGRAMS = YES + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found on the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_WIDTH = 1024 + +# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_HEIGHT = 1024 + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermedate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES + +#--------------------------------------------------------------------------- +# Configuration::addtions related to the search engine +#--------------------------------------------------------------------------- + +# The SEARCHENGINE tag specifies whether or not a search engine should be +# used. If set to NO the values of all tags below this one will be ignored. + +SEARCHENGINE = NO + +# The CGI_NAME tag should be the name of the CGI script that +# starts the search engine (doxysearch) with the correct parameters. +# A script with this name will be generated by doxygen. + +CGI_NAME = search.cgi + +# The CGI_URL tag should be the absolute URL to the directory where the +# cgi binaries are located. See the documentation of your http daemon for +# details. + +CGI_URL = + +# The DOC_URL tag should be the absolute URL to the directory where the +# documentation is located. If left blank the absolute path to the +# documentation, with file:// prepended to it, will be used. + +DOC_URL = + +# The DOC_ABSPATH tag should be the absolute path to the directory where the +# documentation is located. If left blank the directory on the local machine +# will be used. + +DOC_ABSPATH = + +# The BIN_ABSPATH tag must point to the directory where the doxysearch binary +# is installed. + +BIN_ABSPATH = /usr/local/bin/ + +# The EXT_DOC_PATHS tag can be used to specify one or more paths to +# documentation generated for other projects. This allows doxysearch to search +# the documentation for these projects as well. + +EXT_DOC_PATHS = diff --git a/modules/c/nitf/apps/get_nitf_version.c b/modules/c/nitf/apps/get_nitf_version.c new file mode 100644 index 000000000..8720c2d8b --- /dev/null +++ b/modules/c/nitf/apps/get_nitf_version.c @@ -0,0 +1,49 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include + +int main(int argc, char** argv) +{ + nitf_Version version; + if ( argc != 2 ) + { + fprintf(stdout, "Usage: %s \n", argv[0]); + exit(EXIT_FAILURE); + } + + version = nitf_Reader_getNITFVersion(argv[1]); + switch (version) + { + case NITF_VER_20: + fprintf(stdout, "NITF 2.0\n"); + break; + case NITF_VER_21: + fprintf(stdout, "NITF 2.1\n"); + break; + default: + fprintf(stdout, "Unknown\n"); + } + + return 0; +} + diff --git a/modules/c/nitf/apps/image_footprint_kml.c b/modules/c/nitf/apps/image_footprint_kml.c new file mode 100644 index 000000000..5fa3e6d6b --- /dev/null +++ b/modules/c/nitf/apps/image_footprint_kml.c @@ -0,0 +1,183 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ + +#include +/* + * Reads in a NITF record, and generates a KML file for each segment within + * the NITF outlining the boundaries of the footprint. If the image does + * not have an ICORD of 'D' or 'G' (translation, the IGEOLO is not listed + * in geographic or decimal degress), we do nothing + * + */ + + +/* + * We could make this a polygon instead. + * + */ +#define KML_TEMPLATE \ +"\ +\ +%s1\ +\ +%s#s%d\ +%f,%f,0 %f,%f,0 %f,%f,0 %f,%f,0 %f,%f,0\ +" + +/* + * For each image segment, generate a KML file with a bounding + * path. + * + */ +void writeKML(nitf_ImageSubheader* header, + int i, + const char* file) +{ + + nitf_CornersType type = nitf_ImageSubheader_getCornersType(header); + double corners[4][2]; + char buf[1024]; + char outfile[NITF_MAX_PATH]; + nitf_IOHandle out; + nitf_Error error; + + if (type < NITF_CORNERS_GEO) + { + printf("Image subheader has icords [%c]. Ignoring.\n", + nitf_Utils_cornersTypeAsCoordRep(type)); + return; + } + + /* We're in luck! So lets print the footprint to KML! */ + if (!nitf_ImageSubheader_getCornersAsLatLons(header, corners, &error)) + { + nitf_Error_print(&error, stdout, "Bad corners. Ignoring"); + return; + } + + NITF_SNPRINTF(outfile, NITF_MAX_PATH, "%s-%d.kml", file, i+1); + + out = nitf_IOHandle_create(outfile, + NITF_ACCESS_WRITEONLY, + NITF_CREATE, + &error); + + /* KML is lon first! */ + NITF_SNPRINTF(buf, NITF_MAX_PATH, KML_TEMPLATE, outfile, i+1, outfile, i+1, + corners[0][1], corners[0][0], + corners[1][1], corners[1][0], + corners[2][1], corners[2][0], + corners[3][1], corners[3][0], + corners[0][1], corners[0][0]); + + if (!nitf_IOHandle_write(out, buf, strlen(buf), &error)) + { + nitf_Error_print(&error, stdout, "Write failed"); + return; + + } + nitf_IOHandle_close(out); + + +} + +int main(int argc, char** argv) +{ + nitf_Record* record; + nitf_Reader* reader; + nitf_IOHandle io; + nitf_Error error; + char file[NITF_MAX_PATH]; + int i; + nitf_Uint32 num; + + if ( argc != 2 ) + { + fprintf(stdout, "Usage: %s \n", argv[0]); + exit(EXIT_FAILURE); + } + + /* Check if its a NITF */ + if (nitf_Reader_getNITFVersion(argv[1]) == NITF_VER_UNKNOWN) + { + fprintf(stdout, "Invalid NITF: %s\n", argv[1]); + exit(EXIT_FAILURE); + } + + /* Open the file handle */ + io = nitf_IOHandle_create(argv[1], NITF_ACCESS_READONLY, + NITF_OPEN_EXISTING, &error); + + if (NITF_INVALID_HANDLE(io)) + { + nitf_Error_print(&error, stdout, "Exiting..."); + exit(EXIT_FAILURE); + } + + /* Make a reader */ + reader = nitf_Reader_construct(&error); + if (!reader) + { + nitf_Error_print(&error, stdout, "Exiting (1) ..."); + exit(EXIT_FAILURE); + } + + /* This parses all header data within the NITF */ + record = nitf_Reader_read(reader, io, &error); + if (!record) goto CLEANUP; + + + /* Figure out if we have a nitf */ + num = nitf_Record_getNumImages(record, &error); + if (NITF_INVALID_NUM_SEGMENTS( num )) + { + nitf_Error_print(&error, stdout, "Invalid num image segments"); + goto CLEANUP; + } + if (num == 0) + { + printf("No images found in file. Ignoring.\n"); + goto CLEANUP; + } + + nitf_Utils_baseName(file, argv[1], "."); + + for (i = 0; i < num; i++) + { + nitf_ImageSegment* segment = nitf_List_get(record->images, i, &error); + if (!segment) + { + nitf_Error_print(&error, stdout, "Image list retrieval"); + goto CLEANUP; + } + writeKML(segment->subheader, i, file); + } + +CLEANUP: + nitf_IOHandle_close(io); + if (record) nitf_Record_destruct(&record); + if (reader) nitf_Reader_destruct(&reader); + + return 0; +} + diff --git a/modules/c/nitf/apps/show_nitf.c b/modules/c/nitf/apps/show_nitf.c new file mode 100644 index 000000000..6ca22edda --- /dev/null +++ b/modules/c/nitf/apps/show_nitf.c @@ -0,0 +1,930 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + +/* + * These macros are just for retrieving the data simply as raw + * strings. They are not very robust, since we dont bother to check + * here that your data is printable. We do not recommend using this + * approach within your own program. + * + * Typically, you would use the Field conversion functions + * (which are used within the program whenever we are testing + * a value). + */ +#define SHOW(X) printf("%s=[%s]\n", #X, ((X==0)?"(nul)":X)) +#define SHOW_I(X) printf("%s=[%ld]\n", #X, X) +#define SHOW_LLI(X) printf("%s=[%lld]\n", #X, X) +#define SHOW_LLU(X) printf("%s=[%llu]\n", #X, X) + +#define SHOW_RGB(X) \ + printf("%s(R,G,B)=[0x%x,0x%x,0x%x]\n", #X, (short)(X->raw[0]), (short)(X->raw[1]), (short)(X->raw[2])) + +#define SHOW_VAL(X) \ + printf("%s=[%.*s]\n", #X, ((X==0)?8:((X->raw==0)?5:(int)X->length)), \ + ((X==0)?"(nulptr)":((X->raw==0)?"(nul)":X->raw))) + + + +void measureComplexity(nitf_Record* record) +{ + + nitf_Error error; + char str[3]; + NITF_CLEVEL recorded, clevel; + str[2] = 0; + + recorded = nitf_ComplexityLevel_get(record); + + clevel = nitf_ComplexityLevel_measure(record, &error); + + if ((int)recorded != (int)clevel) + { + if (!nitf_ComplexityLevel_toString(clevel, str)) + { + printf("CLEVEL measurement failed"); + nitf_Error_print(&error, stdout, "Measurement problem"); + } + printf("Measured CLEVEL differs from recorded: '%s', ", str); + nitf_ComplexityLevel_toString(recorded, str); + printf("file: '%s'\n", str); + } +} + +/* + * This function dumps a TRE using the TRE enumerator. + * The enumerator is used to walk the fields of a TRE in order + * when the TRE enumerator is expired it will be set to NULL. + * + */ +void printTRE(nitf_TRE* tre) +{ + nitf_Error error; + nitf_Uint32 treLength; + nitf_TREEnumerator* it = NULL; + const char* treID = NULL; + + /* This is just so you know how long the TRE is */ + treLength = tre->handler->getCurrentSize(tre, &error); + + /* + * This is the name for the description that was selected to field + * this TRE by the handler. + */ + treID = nitf_TRE_getID(tre); + + printf("\n--------------- %s TRE (%d) - (%s) ---------------\n", + tre->tag, treLength, treID ? treID : "null id"); + + /* Now walk the TRE */ + it = nitf_TRE_begin(tre, &error); + + while(it && it->hasNext(&it)) + { + /* If this isn't set, it should have been an error */ + nitf_Pair* fieldPair = it->next(it, &error); + if (fieldPair) + { + const char* desc = it->getFieldDescription(it, &error); + printf("%s", fieldPair->key); + if (desc) + printf(" (%s)", desc); + printf(" = ["); + nitf_Field_print((nitf_Field *) fieldPair->data); + printf("]\n"); + } + else + nitf_Error_print(&error, stdout, "Field retrieval error"); + + } + printf("---------------------------------------------\n"); +} + +/* + * This function shows us the best way of walking through + * an extension segment (userDefined or extended) + */ +void showExtensions(nitf_Extensions* ext) +{ + + /* These let you walk an extensions like a list */ + nitf_ExtensionsIterator iter; + nitf_ExtensionsIterator end; + + /* Get the beginning pointer */ + iter = nitf_Extensions_begin(ext); + + /* Get the pointer to end */ + end = nitf_Extensions_end(ext); + + /* Iterations */ + while (nitf_ExtensionsIterator_notEqualTo(&iter, &end) ) + { + nitf_TRE* tre = nitf_ExtensionsIterator_get(&iter); + /* Prints a single TRE */ + printTRE( tre ); + /* Don't forget to increment this */ + nitf_ExtensionsIterator_increment(&iter); + } +} + +/* + * This function dumps the security header. + * + */ +void showSecurityGroup(nitf_FileSecurity* securityGroup) +{ + + assert( securityGroup ); + + SHOW_VAL(securityGroup->classificationSystem); + SHOW_VAL(securityGroup->codewords); + SHOW_VAL(securityGroup->controlAndHandling); + SHOW_VAL(securityGroup->releasingInstructions); + SHOW_VAL(securityGroup->declassificationType); + SHOW_VAL(securityGroup->declassificationDate); + SHOW_VAL(securityGroup->declassificationExemption); + SHOW_VAL(securityGroup->downgrade); + SHOW_VAL(securityGroup->downgradeDateTime); + SHOW_VAL(securityGroup->classificationText); + SHOW_VAL(securityGroup->classificationAuthorityType); + SHOW_VAL(securityGroup->classificationAuthority); + SHOW_VAL(securityGroup->classificationReason); + SHOW_VAL(securityGroup->securitySourceDate); + SHOW_VAL(securityGroup->securityControlNumber); +} + +/* + * The file header contains information that is relevant + * to the entire file, including subheader and segment + * lengths, file length, header length, and security level + * for the file. + */ +void showFileHeader(nitf_Record * record) +{ + unsigned int i; + nitf_Uint32 num; + nitf_Error error; + nitf_Uint32 len; + nitf_Uint64 dataLen; + nitf_Uint32 dataLen32; + nitf_Version fver; + nitf_FileHeader *header; + + fver = nitf_Record_getVersion(record); + + /* Sanity check */ + assert( record ); + header = record->header; + assert( header ); + + /* Dump the values in order */ + SHOW_VAL(header->fileHeader); + SHOW_VAL(header->fileVersion); + SHOW_VAL(header->complianceLevel); + SHOW_VAL(header->systemType); + SHOW_VAL(header->originStationID); + SHOW_VAL(header->fileDateTime); + SHOW_VAL(header->fileTitle); + SHOW_VAL(header->classification); + + if (*(header->classification->raw) != 'U') + showSecurityGroup(header->securityGroup); + + SHOW_VAL(header->messageCopyNum); + SHOW_VAL(header->messageNumCopies); + SHOW_VAL(header->encrypted); + + if (IS_NITF21(fver)) + SHOW_RGB(header->backgroundColor); + SHOW_VAL(header->originatorName); + SHOW_VAL(header->originatorPhone); + SHOW_VAL(header->fileLength); + SHOW_VAL(header->headerLength); + + if (!nitf_Field_get(header->numImages, + &num, NITF_CONV_INT, NITF_INT32_SZ, &error)) + goto CATCH_ERROR; + + + printf("The number of images contained in this file [%lu]\n", num); + for (i = 0; i < num; i++) + { + + if (!nitf_Field_get(header->imageInfo[i]->lengthSubheader, + &len, NITF_CONV_INT, NITF_INT32_SZ, &error)) + goto CATCH_ERROR; + + if (!nitf_Field_get(header->imageInfo[i]->lengthData, + &dataLen, + NITF_CONV_INT, NITF_INT64_SZ, &error)) + goto CATCH_ERROR; + + printf("\tThe length of image subheader [%u]: %lu bytes\n", + i, len); + printf("\tThe length of the image data: %llu bytes\n\n", dataLen); + } + + if (!nitf_Field_get(header->numGraphics, + &num, NITF_CONV_INT, NITF_INT32_SZ, &error)) + goto CATCH_ERROR; + + + printf("The number of graphics contained in this file [%ld]\n", num); + for (i = 0; i < num; i++) + { + + if (!nitf_Field_get(header->graphicInfo[i]->lengthSubheader, + &len, NITF_CONV_INT, NITF_INT32_SZ, &error)) + goto CATCH_ERROR; + + if (!nitf_Field_get(header->graphicInfo[i]->lengthData, + &dataLen32, + NITF_CONV_INT, NITF_INT32_SZ, &error)) + goto CATCH_ERROR; + + printf("\tThe length of graphic subheader [%u]: %lu bytes\n", + i, len); + printf("\tThe length of the graphic data: %lu bytes\n\n", + dataLen32); + } + + if (!nitf_Field_get(header->numLabels, + &num, NITF_CONV_INT, NITF_INT32_SZ, &error)) + goto CATCH_ERROR; + + printf("The number of labels contained in this file [%ld]\n", num); + for (i = 0; i < num; i++) + { + + if (!nitf_Field_get(header->labelInfo[i]->lengthSubheader, + &len, NITF_CONV_INT, NITF_INT32_SZ, &error)) + goto CATCH_ERROR; + + if (!nitf_Field_get(header->labelInfo[i]->lengthData, + &dataLen32, + NITF_CONV_INT, NITF_INT32_SZ, &error)) + goto CATCH_ERROR; + printf("\tThe length of label subheader [%u]: %lu bytes\n", + i, len); + + printf("\tThe length of the label data: %lu bytes\n\n", + dataLen32); + } + + if (!nitf_Field_get(header->numTexts, + &num, NITF_CONV_INT, NITF_INT32_SZ, &error)) + goto CATCH_ERROR; + + printf("The number of text sections contained in this file [%ld]\n", + num); + + for (i = 0; i < num; i++) + { + if (!nitf_Field_get(header->textInfo[i]->lengthSubheader, + &len, NITF_CONV_INT, NITF_INT32_SZ, &error)) + goto CATCH_ERROR; + + if (!nitf_Field_get(header->textInfo[i]->lengthData, + &dataLen32, + NITF_CONV_INT, NITF_INT32_SZ, &error)) + goto CATCH_ERROR; + + printf("\tThe length of text subheader [%u]: %lu bytes\n", + i, len); + + printf("\tThe length of the text data: %lu bytes\n\n", + dataLen32); + } + + if (!nitf_Field_get(header->numDataExtensions, + &num, NITF_CONV_INT, NITF_INT32_SZ, &error)) + goto CATCH_ERROR; + + printf("The number of DES contained in this file [%ld]\n", + num); + + for (i = 0; i < num; i++) + { + if (!nitf_Field_get(header->dataExtensionInfo[i]->lengthSubheader, + &len, NITF_CONV_INT, NITF_INT32_SZ, &error)) + goto CATCH_ERROR; + + if (!nitf_Field_get(header->dataExtensionInfo[i]->lengthData, + &dataLen32, + NITF_CONV_INT, NITF_INT32_SZ, &error)) + goto CATCH_ERROR; + + printf("\tThe length of DES subheader [%u]: %lu bytes\n", + i, len); + printf("\tThe length of the DES data: %lu bytes\n\n", + dataLen32); + } + + + if (!nitf_Field_get(header->numReservedExtensions, + &num, NITF_CONV_INT, NITF_INT32_SZ, &error)) + goto CATCH_ERROR; + + printf("The number of RES contained in this file [%ld]\n", + num); + + for (i = 0; i < num; i++) + { + + + if (!nitf_Field_get + (header->reservedExtensionInfo[i]->lengthSubheader, &len, + NITF_CONV_INT, NITF_INT32_SZ, &error)) + goto CATCH_ERROR; + + if (!nitf_Field_get(header->reservedExtensionInfo[i]->lengthData, + &dataLen32, + NITF_CONV_INT, NITF_INT32_SZ, &error)) + goto CATCH_ERROR; + + printf("\tThe length of RES subheader [%u]: %lu bytes\n", + i, len); + + printf("\tThe length of the RES data: %lu bytes\n\n", + dataLen32); + } + + if (!nitf_Field_get(header->userDefinedHeaderLength, &num, + NITF_CONV_INT, NITF_INT32_SZ, &error)) + goto CATCH_ERROR; + + printf("The user-defined header length [%ld]\n", num); + + if (header->userDefinedSection) + showExtensions( header->userDefinedSection ); + + if (!nitf_Field_get(header->extendedHeaderLength, &num, + NITF_CONV_INT, NITF_INT32_SZ, &error)) + goto CATCH_ERROR; + + printf("The extended header length [%ld]\n", num); + + if (header->extendedSection) + showExtensions( header->extendedSection ); + + return; + +CATCH_ERROR: + printf("Error processing\n"); +} + +/* + * Show the image subheader. This contains information + * about a specific segment. That includes the pixel interleaving, + * block info, pixel information and band info. + * + */ +void showImageSubheader(nitf_ImageSubheader * sub) +{ + int q; + int nbands, xbands; + nitf_Error error; + int ncomments; + nitf_ListIterator iter, end; + nitf_CornersType cornersType; + assert( sub ); + + if (!nitf_Field_get(sub->numImageComments, + &ncomments, NITF_CONV_INT, NITF_INT32_SZ, &error)) + { + goto CATCH_ERROR; + } + + printf("image subheader:\n"); + SHOW_VAL(sub->filePartType); + SHOW_VAL(sub->imageId); + SHOW_VAL(sub->imageDateAndTime); + SHOW_VAL(sub->targetId); + SHOW_VAL(sub->imageTitle); + SHOW_VAL(sub->imageSecurityClass); + + if (*(sub->imageSecurityClass->raw) != 'U') + showSecurityGroup(sub->securityGroup); + + SHOW_VAL(sub->encrypted); + SHOW_VAL(sub->imageSource); + SHOW_VAL(sub->numRows); + SHOW_VAL(sub->numCols); + SHOW_VAL(sub->pixelValueType); + SHOW_VAL(sub->imageRepresentation); + SHOW_VAL(sub->imageCategory); + SHOW_VAL(sub->actualBitsPerPixel); + SHOW_VAL(sub->pixelJustification); + SHOW_VAL(sub->imageCoordinateSystem); + SHOW_VAL(sub->cornerCoordinates); + + cornersType = nitf_ImageSubheader_getCornersType(sub); + + if (cornersType == NITF_CORNERS_GEO || + cornersType == NITF_CORNERS_DECIMAL) + { + double corners[4][2]; + + if (!nitf_ImageSubheader_getCornersAsLatLons(sub, corners, &error)) + { + nitf_Error_print(&error, stdout, "Warning: Corners appear to be invalid!"); + } + else + { + printf("(0,0): (%f, %f)\n", corners[0][0], corners[0][1]); + printf("(0,C): (%f, %f)\n", corners[1][0], corners[1][1]); + printf("(R,C): (%f, %f)\n", corners[2][0], corners[2][1]); + printf("(R,0): (%f, %f)\n", corners[3][0], corners[3][1]); + + } + + } + + + + SHOW_VAL(sub->numImageComments); + + iter = nitf_List_begin(sub->imageComments); + end = nitf_List_end(sub->imageComments); + while (nitf_ListIterator_notEqualTo(&iter, &end)) + { + nitf_Field* commentField = (nitf_Field*) nitf_ListIterator_get(&iter); + SHOW_VAL(commentField); + nitf_ListIterator_increment(&iter); + } + + SHOW_VAL(sub->imageCompression); + SHOW_VAL(sub->compressionRate); + + SHOW_VAL(sub->numImageBands); + SHOW_VAL(sub->numMultispectralImageBands); + + if (!nitf_Field_get(sub->numImageBands, &nbands, + NITF_CONV_INT, NITF_INT32_SZ, &error)) + goto CATCH_ERROR; + + + if (!nitf_Field_get(sub->numMultispectralImageBands, &xbands, + NITF_CONV_INT, NITF_INT32_SZ, &error)) + goto CATCH_ERROR; + + + nbands += xbands; + for (q = 0; q < nbands; q++) + { + SHOW_VAL(sub->bandInfo[q]->representation); + SHOW_VAL(sub->bandInfo[q]->subcategory); + SHOW_VAL(sub->bandInfo[q]->imageFilterCondition); + SHOW_VAL(sub->bandInfo[q]->imageFilterCode); + SHOW_VAL(sub->bandInfo[q]->numLUTs); + SHOW_VAL(sub->bandInfo[q]->bandEntriesPerLUT); + } + + /* Skip band stuff for now */ + SHOW_VAL(sub->imageSyncCode); + SHOW_VAL(sub->imageMode); + SHOW_VAL(sub->numBlocksPerRow); + SHOW_VAL(sub->numBlocksPerCol); + SHOW_VAL(sub->numPixelsPerHorizBlock); + SHOW_VAL(sub->numPixelsPerVertBlock); + SHOW_VAL(sub->numBitsPerPixel); + SHOW_VAL(sub->imageDisplayLevel); + SHOW_VAL(sub->imageAttachmentLevel); + SHOW_VAL(sub->imageLocation); + SHOW_VAL(sub->imageMagnification); + + SHOW_VAL(sub->userDefinedImageDataLength); + SHOW_VAL(sub->userDefinedOverflow); + + if (sub->userDefinedSection) + showExtensions( sub->userDefinedSection ); + + SHOW_VAL(sub->extendedHeaderLength); + SHOW_VAL(sub->extendedHeaderOverflow); + + if (sub->extendedSection) + showExtensions( sub->extendedSection ); + return; + +CATCH_ERROR: + printf("Error processing\n"); + +} + +/* + * This section is for vector graphics. Currently + * this will be CGM 1.0 (there is a spec for NITF CGM, + * but the original CGM 1.0 spec is out-of-print. + * + * Note that this function does not dump the binary CGM + * You can use the NITRO CGM library to read the CGM data + * from the NITF (and dump it) + */ +void showGraphicSubheader(nitf_GraphicSubheader * sub) +{ + assert( sub ); + + printf("graphic subheader:\n"); + SHOW_VAL(sub->filePartType); + SHOW_VAL(sub->graphicID); + SHOW_VAL(sub->name); + SHOW_VAL(sub->securityClass); + + if (*(sub->securityClass->raw) != 'U') + showSecurityGroup(sub->securityGroup); + + SHOW_VAL(sub->encrypted); + SHOW_VAL(sub->stype); + SHOW_VAL(sub->res1); + SHOW_VAL(sub->displayLevel); + SHOW_VAL(sub->attachmentLevel); + SHOW_VAL(sub->location); + SHOW_VAL(sub->bound1Loc); + SHOW_VAL(sub->color); + SHOW_VAL(sub->bound2Loc); + SHOW_VAL(sub->res2); + SHOW_VAL(sub->extendedHeaderLength); + SHOW_VAL(sub->extendedHeaderOverflow); + if (sub->extendedSection) + showExtensions( sub->extendedSection ); +} + +/* + * Label was superceded for NITF 2.1 + * + */ +void showLabelSubheader(nitf_LabelSubheader * sub) +{ + assert( sub ); + printf("label subheader\n"); + SHOW_VAL(sub->filePartType); + SHOW_VAL(sub->labelID); + SHOW_VAL(sub->securityClass); + + if (*(sub->securityClass->raw) != 'U') + showSecurityGroup(sub->securityGroup); + + SHOW_VAL(sub->encrypted); + SHOW_VAL(sub->fontStyle); + SHOW_VAL(sub->cellWidth); + SHOW_VAL(sub->cellHeight); + SHOW_VAL(sub->displayLevel); + SHOW_VAL(sub->attachmentLevel); + SHOW_VAL(sub->locationRow); + SHOW_VAL(sub->locationColumn); + SHOW_RGB(sub->textColor); + SHOW_RGB(sub->backgroundColor); + SHOW_VAL(sub->extendedHeaderLength); + SHOW_VAL(sub->extendedHeaderOverflow); + if (sub->extendedSection) + showExtensions( sub->extendedSection ); +} + +/* + * This section contains raw text data. You can put + * lots of stuff in here but most people never do. + * + * Note that XML data is usually not contained in this section + * even though that might have made more sense. XML data is + * typically found in the DES segment + */ +void showTextSubheader(nitf_TextSubheader * sub) +{ + assert( sub ); + + printf("text subheader\n"); + SHOW_VAL(sub->filePartType); + SHOW_VAL(sub->textID); + SHOW_VAL(sub->attachmentLevel); + SHOW_VAL(sub->dateTime); + SHOW_VAL(sub->title); + SHOW_VAL(sub->securityClass); + + if (*(sub->securityClass->raw) != 'U') + showSecurityGroup(sub->securityGroup); + + SHOW_VAL(sub->encrypted); + SHOW_VAL(sub->format); + SHOW_VAL(sub->extendedHeaderLength); + SHOW_VAL(sub->extendedHeaderOverflow); + if (sub->extendedSection) + showExtensions(sub->extendedSection); +} +/* + * This section is for dumping the Data Extension Segment (DES) + * subheader. It can hold up to 1GB worth of data, so its big + * enough for most things. People stuff all kinds of things in + * the DESDATA block including + * + * - TRE overflow: + * When a TRE is too big for the section its in. In other words, + * if populating it properly would overflow the segment, it is + * dumped into the TRE overflow segment. + * + * This is kind of a pain, and so NITRO 2.0 has functions to + * split this up for you, or merge it back into the header where it + * would go if it wasnt too big (see nitf_Record_mergeTREs() and + * nitf_Record_unmergeTREs). + * + * However, by default, we assume that you want the data as it + * appeared in the file. Therefore, when you dump a record, you + * might see overflow data + * + * - Text data (especially XML) + * + * XML data is getting more popular, and to make sure that they + * dont have to worry about the length of the XML surpassing the + * limits of a segment, most people decide to spec. it to go here + * + * - Binary data + * + * Since the DES is the wild west of the NITF, you can put anything + * you want here. + * + * Confusingly, the DES subheader has its own little TRE-like + * arbitrary key-value params. In NITRO we treat this as a TRE within + * the subheader. + * + * This function prints the DE subheader, the extended TRE described above, + * and additionally, if the DESDATA is TRE overflow, we dump those too. + */ +void showDESubheader(nitf_DESubheader * sub) +{ + assert( sub ); + + printf("DES subheader\n"); + SHOW_VAL(sub->filePartType); + SHOW_VAL(sub->typeID); + SHOW_VAL(sub->version); + SHOW_VAL(sub->securityClass); + + if (*(sub->securityClass->raw) != 'U') + showSecurityGroup(sub->securityGroup); + + SHOW_VAL(sub->overflowedHeaderType); + SHOW_VAL(sub->dataItemOverflowed); + SHOW_VAL(sub->subheaderFieldsLength); + + /* + * This is the user defined parameter section + * within the DES. It contains only BCS-A/N type values + * so storing it in a 'TRE' struct is no big deal + */ + if (sub->subheaderFields) + printTRE(sub->subheaderFields); + + SHOW_LLU(sub->dataLength); + + /* + * NITRO only populates this object if the DESDATA contains + * TRE overflow. Otherwise, you need to use a DEReader to + * get at the DESDATA, since it can contain anything. + * + * We wont bother to try and print whatever other things might + * have been put in here (e.g, text data or binary blobs) + */ + if (sub->userDefinedSection) + showExtensions( sub->userDefinedSection ); +} + +/* + * This section is never really populated + */ +void showRESubheader(nitf_RESubheader * sub) +{ + assert( sub ); + + printf("RES subheader\n"); + SHOW_VAL(sub->filePartType); + SHOW_VAL(sub->typeID); + SHOW_VAL(sub->version); + SHOW_VAL(sub->securityClass); + + if (*(sub->securityClass->raw) != 'U') + showSecurityGroup(sub->securityGroup); + + SHOW_VAL(sub->subheaderFieldsLength); + SHOW_LLU(sub->dataLength); +} + +int main(int argc, char **argv) +{ + /* Get the error object */ + nitf_Error error; + + /* This is the reader object */ + nitf_Reader *reader; + nitf_Record *record; + + /* The IO handle */ + nitf_IOHandle io; + int num; + + /* Check argv and make sure we are happy */ + if (argc != 2) + { + printf("Usage: %s \n", argv[0]); + exit(EXIT_FAILURE); + } + + /* You should use this function to test that you have a valid NITF */ + if (nitf_Reader_getNITFVersion( argv[1] ) == NITF_VER_UNKNOWN) + { + printf("This file does not appear to be a valid NITF\n"); + exit(EXIT_FAILURE); + } + + + + /* + * Using an IO handle is one valid way to read a NITF in + * + * NITRO 2.5 offers other ways, using the readIO() function + * in the Reader + */ + io = nitf_IOHandle_create(argv[1], NITF_ACCESS_READONLY, + NITF_OPEN_EXISTING, &error); + if (NITF_INVALID_HANDLE(io)) + { + nitf_Error_print(&error, stdout, "Exiting..."); + exit(EXIT_FAILURE); + } + + /* We need to make a reader so we can parse the NITF */ + reader = nitf_Reader_construct(&error); + if (!reader) + { + nitf_Error_print(&error, stdout, "Exiting (1) ..."); + exit(EXIT_FAILURE); + } + + /* This parses all header data within the NITF */ + record = nitf_Reader_read(reader, io, &error); + if (!record) goto CATCH_ERROR; + + /* Now show the header */ + showFileHeader(record); + + num = nitf_Record_getNumImages(record, &error); + + if (NITF_INVALID_NUM_SEGMENTS( num ) ) + goto CATCH_ERROR; + + /* And now show the image information */ + if (num) + { + /* Walk each image and show */ + nitf_ListIterator iter = nitf_List_begin(record->images); + nitf_ListIterator end = nitf_List_end(record->images); + + while (nitf_ListIterator_notEqualTo(&iter, &end)) + { + nitf_ImageSegment *segment = + (nitf_ImageSegment *) nitf_ListIterator_get(&iter); + showImageSubheader(segment->subheader); + nitf_ListIterator_increment(&iter); + } + } + else + { + printf("No image in file!\n"); + } + + num = nitf_Record_getNumGraphics(record, &error); + if (NITF_INVALID_NUM_SEGMENTS( num ) ) + goto CATCH_ERROR; + + if (num) + { + /* Walk each graphic and show */ + nitf_ListIterator iter = nitf_List_begin(record->graphics); + nitf_ListIterator end = nitf_List_end(record->graphics); + + while (nitf_ListIterator_notEqualTo(&iter, &end)) + { + nitf_GraphicSegment *segment = + (nitf_GraphicSegment *) nitf_ListIterator_get(&iter); + + showGraphicSubheader(segment->subheader); + nitf_ListIterator_increment(&iter); + } + } + + num = nitf_Record_getNumLabels(record, &error); + if (NITF_INVALID_NUM_SEGMENTS( num ) ) + goto CATCH_ERROR; + + if (num) + { + /* Walk each label and show */ + nitf_ListIterator iter = nitf_List_begin(record->labels); + nitf_ListIterator end = nitf_List_end(record->labels); + + while (nitf_ListIterator_notEqualTo(&iter, &end)) + { + nitf_LabelSegment *segment = + (nitf_LabelSegment *) nitf_ListIterator_get(&iter); + + showLabelSubheader(segment->subheader); + nitf_ListIterator_increment(&iter); + } + } + + num = nitf_Record_getNumTexts(record, &error); + if (NITF_INVALID_NUM_SEGMENTS( num ) ) + goto CATCH_ERROR; + + if (num) + { + /* Walk each text and show */ + nitf_ListIterator iter = nitf_List_begin(record->texts); + nitf_ListIterator end = nitf_List_end(record->texts); + + while (nitf_ListIterator_notEqualTo(&iter, &end)) + { + nitf_TextSegment *segment = + (nitf_TextSegment *) nitf_ListIterator_get(&iter); + + showTextSubheader(segment->subheader); + nitf_ListIterator_increment(&iter); + } + } + + + num = nitf_Record_getNumDataExtensions(record, &error); + if (NITF_INVALID_NUM_SEGMENTS( num ) ) + goto CATCH_ERROR; + + if (num) + { + /* Walk each dataExtension and show */ + nitf_ListIterator iter = nitf_List_begin(record->dataExtensions); + nitf_ListIterator end = nitf_List_end(record->dataExtensions); + + while (nitf_ListIterator_notEqualTo(&iter, &end)) + { + nitf_DESegment *segment = + (nitf_DESegment *) nitf_ListIterator_get(&iter); + + showDESubheader(segment->subheader); + nitf_ListIterator_increment(&iter); + } + } + + num = nitf_Record_getNumReservedExtensions(record, &error); + if (NITF_INVALID_NUM_SEGMENTS( num ) ) + goto CATCH_ERROR; + + if (num) + { + /* Walk each reservedextension and show */ + nitf_ListIterator iter = + nitf_List_begin(record->reservedExtensions); + nitf_ListIterator end = nitf_List_end(record->reservedExtensions); + + while (nitf_ListIterator_notEqualTo(&iter, &end)) + { + nitf_RESegment *segment = + (nitf_RESegment *) nitf_ListIterator_get(&iter); + + showRESubheader(segment->subheader); + nitf_ListIterator_increment(&iter); + } + } + + /*measureComplexity(record);*/ + + nitf_IOHandle_close(io); + nitf_Record_destruct(&record); + nitf_Reader_destruct(&reader); + + return 0; + +CATCH_ERROR: + printf("We had a problem reading the file\n"); + nitf_Error_print(&error, stdout, "Exiting..."); + exit(EXIT_FAILURE); +} + + diff --git a/modules/c/nitf/apps/wscript b/modules/c/nitf/apps/wscript new file mode 100644 index 000000000..8084fc253 --- /dev/null +++ b/modules/c/nitf/apps/wscript @@ -0,0 +1,12 @@ +import os, subprocess +from waflib import Options +from os.path import splitext, dirname, join + +configure = options = distclean = lambda p: None + +def build(bld): + apps = bld.path.ant_glob('*.c') + for app in apps: + filename = str(app) + bld.program_helper(dir='apps', source=filename, module_deps='nitf', name=filename[:-2], + lang='c') \ No newline at end of file diff --git a/modules/c/nitf/include/import/nitf.h b/modules/c/nitf/include/import/nitf.h new file mode 100644 index 000000000..b83303341 --- /dev/null +++ b/modules/c/nitf/include/import/nitf.h @@ -0,0 +1,70 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __IMPORT_NITF_H__ +#define __IMPORT_NITF_H__ + +#include "nitf/BandInfo.h" +#include "nitf/BandSource.h" +#include "nitf/ComponentInfo.h" +#include "nitf/DESegment.h" +#include "nitf/DESubheader.h" +#include "nitf/DefaultTRE.h" +#include "nitf/DownSampler.h" +#include "nitf/Extensions.h" +#include "nitf/Field.h" +#include "nitf/FieldWarning.h" +#include "nitf/FileHeader.h" +#include "nitf/FileSecurity.h" +#include "nitf/GraphicSegment.h" +#include "nitf/GraphicSubheader.h" +#include "nitf/ImageIO.h" +#include "nitf/ImageReader.h" +#include "nitf/ImageSegment.h" +#include "nitf/ImageSource.h" +#include "nitf/ImageSubheader.h" +#include "nitf/ImageWriter.h" +#include "nitf/LabelSegment.h" +#include "nitf/LabelSubheader.h" +#include "nitf/LookupTable.h" +#include "nitf/PluginIdentifier.h" +#include "nitf/PluginRegistry.h" +#include "nitf/RESegment.h" +#include "nitf/RESubheader.h" +#include "nitf/RowSource.h" +#include "nitf/Reader.h" +#include "nitf/Record.h" +#include "nitf/SegmentReader.h" +#include "nitf/SegmentSource.h" +#include "nitf/StreamIOWriteHandler.h" +#include "nitf/SubWindow.h" +#include "nitf/System.h" +#include "nitf/TRE.h" +#include "nitf/TREUtils.h" +#include "nitf/TextSegment.h" +#include "nitf/TextSubheader.h" +#include "nitf/WriteHandler.h" +#include "nitf/Writer.h" +#include "nitf/DirectBlockSource.h" +#include "nitf/WriterOptions.h" + +#endif diff --git a/modules/c/nitf/include/nitf/BandInfo.h b/modules/c/nitf/include/nitf/BandInfo.h new file mode 100644 index 000000000..0aa850d81 --- /dev/null +++ b/modules/c/nitf/include/nitf/BandInfo.h @@ -0,0 +1,128 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_BAND_INFO_H__ +#define __NITF_BAND_INFO_H__ + +#include "nitf/LookupTable.h" +#include "nitf/System.h" +#include "nitf/Field.h" + + +#define NITF_IREPBAND_SZ 2 +#define NITF_ISUBCAT_SZ 6 +#define NITF_IFC_SZ 1 +#define NITF_IMFLT_SZ 3 +#define NITF_NLUTS_SZ 1 +#define NITF_NELUT_SZ 5 + +#define NITF_IREPBAND representation +#define NITF_ISUBCAT subcategory +#define NITF_IFC imageFilterCondition +#define NITF_IMFLT imageFilterCode +#define NITF_NLUTS numLUTs +#define NITF_NELUT bandEntriesPerLUT + +NITF_CXX_GUARD + +/*! + * \struct nitf_BandInfo + * \brief The object representing image band information + * + * The BandInfo object is stored in the image subheader, and + * contains information about the bands, including any Lookup + * Tables, and information about band representation. + */ +typedef struct _nitf_BandInfo +{ + nitf_Field *representation; + nitf_Field *subcategory; + nitf_Field *imageFilterCondition; + nitf_Field *imageFilterCode; + nitf_Field *numLUTs; + nitf_Field *bandEntriesPerLUT; + nitf_LookupTable *lut; +} +nitf_BandInfo; + +/*! + * Constructor for a BandInfo object. All internal values + * are constructed to size, with the default fill. The lookup + * table is set to NULL to start. + * + * \param error An error to populate on a NULL return + * \return The newly allocated bandInfo object, or NULL upon failure + * + */ +NITFAPI(nitf_BandInfo *) nitf_BandInfo_construct(nitf_Error * error); + + +/*! + * Destruct all sub-objects, and make sure that we + * kill this object too. + * + * \param info The BandInfo to destroy. We point info at NULL. + */ +NITFAPI(void) nitf_BandInfo_destruct(nitf_BandInfo ** info); + + +/*! + * Clone this object. This is a deep copy operation. The lut + * is set to NULL if the source has none, and otherwise, is a + * deep copy of the LUT (clone). + * + * \param source The source object + * \param error An error to populate upon failure + * \return A new object that is identical to the old + */ +NITFPROT(nitf_BandInfo *) nitf_BandInfo_clone(nitf_BandInfo * source, + nitf_Error * error); + +/*! + * \brief nitf_BandInfo_init - Initialize a band info object + * + * nitf_BandInfo_init initialize a band info table object. The caller must + * ( supply an existing object, this function does not construct one. + * + * Any of the string arguments can be NULL in which case the default value + * is used. + * + * The object retains a refference to the lut argument, it does not make a + * copy + * + * \return FALSE is returned on error and the supplied error object is set + */ +NITFAPI(NITF_BOOL) nitf_BandInfo_init(nitf_BandInfo * bandInfo, /*!< The band info to initialize */ + const char *representation, /*!< The band representation */ + const char *subcategory, /*!< The band subcategory */ + const char *imageFilterCondition, /*!< The band filter condition */ + const char *imageFilterCode, /*!< The band standard image filter code */ + nitf_Uint32 numLUTs, /*!< The number of look-up tables */ + nitf_Uint32 bandEntriesPerLUT, /*!< The number of entries/LUT */ + nitf_LookupTable * lut, /*!< The look-up tables */ + nitf_Error * error /*!< Error object for error returns */ + ); + + +NITF_CXX_ENDGUARD + +#endif diff --git a/modules/c/nitf/include/nitf/BandSource.h b/modules/c/nitf/include/nitf/BandSource.h new file mode 100644 index 000000000..82879718b --- /dev/null +++ b/modules/c/nitf/include/nitf/BandSource.h @@ -0,0 +1,121 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_BAND_SOURCE_H__ +#define __NITF_BAND_SOURCE_H__ + +#include "nitf/System.h" +#include "nitf/DataSource.h" +#include "nitf/ImageReader.h" + +NITF_CXX_GUARD +/*! + * TODO: We should offer an IOInterface source + * + */ + +/*! + * Typedef nitf_BandSource + */ +typedef nitf_DataSource nitf_BandSource; + +/*! + * Define nitf_BandSource_destruct which is just + * nitf_DataSource_destruct + */ +#define nitf_BandSource_destruct nitf_DataSource_destruct + + + +/*! + * \fn nitf_MemorySource_construct + * \brief A class for reading one band from memory (or VM) + * + * The memory source class allows us to read directly from + * a data buffer. In the event that this is a memory-mapped file, + * we will likely get a performance gain over the direct fd approach. + * + * The constructor takes in a buffer, a size, and optionally + * a sampling factor (Typically, the factor will be applied most + * times during the case of memory mapping, although it may + * be used to sample down or cut the image into pieces). + * + * Contains a static declaration of the specific implementation. + * + * \param data The data + * \param size The size + * \param start The start offset + * \param numBytesPerPixel the number of bytes per pixel + * (if pixelSkip is equal to 0, then numBytesPerPixel is ignored) + * \param pixelSkip The amount of pixels to skip (0 signifies contiguous read) + * (this will get multipled by numBytesPerPixel to figure + * out how many actual bytes to skip) + */ +NITFAPI(nitf_BandSource *) nitf_MemorySource_construct(char *data, + nitf_Off size, + nitf_Off start, + int numBytesPerPixel, + int pixelSkip, + nitf_Error * error); + +/*! + * \fn nitf_FileSource_construct + * \brief Provides impl for reading one band from an FD or HANDLE + * + * The FileSource class is a BandSource that comes from an open + * file descriptor or handle. Due to any number of constraints, + * not the least of which is the band interleaved by pixel case, + * we allow the creator to specify a start point, and a pixel skip + * (this would help you create a thumbnail as well). + * + * Construct a file source from a handle, a start point, and + * a pixel skip. + * + * \param fname The file to use + * \param start The location to seek to (as the beginning) + * \param numBytesPerPixel the number of bytes per pixel + * (if pixelSkip is equal to 0, then numBytesPerPixel is ignored) + * \param pixelSkip The amount of pixels to skip (0 signifies contiguous read) + * (this will get multipled by numBytesPerPixel to figure + * out how many actual bytes to skip) + */ +NITFAPI(nitf_BandSource *) nitf_FileSource_construct(nitf_IOHandle, + nitf_Off start, + int numBytesPerPixel, + int pixelSkip, + nitf_Error * error); + +NITFAPI(nitf_BandSource *) nitf_FileSource_constructFile(const char* fname, + nitf_Off start, + int numBytesPerPixel, + int pixelSkip, + nitf_Error* error); + +NITFAPI(nitf_BandSource *) nitf_IOSource_construct(nitf_IOInterface *io, + nitf_Off start, + int numBytesPerPixel, + int pixelSkip, + nitf_Error * error); + +NITF_CXX_ENDGUARD + +#endif diff --git a/modules/c/nitf/include/nitf/ComplexityLevel.h b/modules/c/nitf/include/nitf/ComplexityLevel.h new file mode 100644 index 000000000..0511566a3 --- /dev/null +++ b/modules/c/nitf/include/nitf/ComplexityLevel.h @@ -0,0 +1,90 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; + * If not, see . + * + */ + +#ifndef __NITF_COMPLEXITY_LEVEL_H__ +#define __NITF_COMPLEXITY_LEVEL_H__ + +#include "nitf/Record.h" +#include "nitf/System.h" + +NITF_CXX_GUARD + +/*! + * This file makes it easy to compute and recompute the CLEVEL. + * It only works on 2.1 files, not on legacy 2.0. + * + */ + +typedef enum _NITF_CLEVEL +{ + NITF_CLEVEL_UNKNOWN = 0, + NITF_CLEVEL_03 = 3, + NITF_CLEVEL_05 = 5, + NITF_CLEVEL_06 = 6, + NITF_CLEVEL_07 = 7, + NITF_CLEVEL_09 = 9, + NITF_CLEVEL_CHECK_FAILED = 10 +} NITF_CLEVEL; + +/*! + * This function attempts to measure the CLEVEL of a NITF 2.1 record. + * The record should be populated with all of the meta-data, so that it + * can be measured. + * + * This function is 'class-static' in the sense that we provide no + * ComplexityLevel class publicly. Internally, its represented as a set + * of function pointers that act on the nitf_Record. + * + * This API call is new for 2.5. As of 2.5, the Writer will + * also use this function internally to checking if a Record's + * complexity level has not yet been set, and if not, it will + * attempt to auto-calculate it. + * + * \param record The input record (its clevel is not modified for this op) + * + * \param error [output] Contains an error if one exists (in which case + * the return value will be NITF_CLEVEL_CHECK_FAILED + * + * \return A clevel if determined, NITF_CLEVEL_CHECK_FAILED on error + * + */ +NITFAPI(NITF_CLEVEL) nitf_ComplexityLevel_measure(nitf_Record* record, + nitf_Error* error); + +/*! + * Get the CLEVEL as recorded in the file + * \return The CLEVEL, unknown if not 03,05,06,07 or 09 + */ +NITFAPI(NITF_CLEVEL) nitf_ComplexityLevel_get(nitf_Record* record); + +/*! + * Turn the enumeration into a 2-byte char. This function should + * probably be renamed to toArray, since it does not write any NULL + * byte at the end (just a memcpy of 2 bytes) + * + */ +NITFAPI(NITF_BOOL) nitf_ComplexityLevel_toString(NITF_CLEVEL clevel, + char* c2); + +NITF_CXX_ENDGUARD + +#endif diff --git a/modules/c/nitf/include/nitf/ComponentInfo.h b/modules/c/nitf/include/nitf/ComponentInfo.h new file mode 100644 index 000000000..e26edd769 --- /dev/null +++ b/modules/c/nitf/include/nitf/ComponentInfo.h @@ -0,0 +1,82 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_COMPONENT_INFO_H__ +#define __NITF_COMPONENT_INFO_H__ + +#include "nitf/System.h" +#include "nitf/Field.h" + +NITF_CXX_GUARD + +/*! + * \struct nitf_ComponentInfo + * \brief Carries information about the images, graphics, text, or extension + * components contained within the file. + * + * The fields from this class are described in the + * file header. They contain information about some component section + * contained in a NITF 2.1 file. + */ +typedef struct _nitf_ComponentInfo +{ + nitf_Field *lengthSubheader; + nitf_Field *lengthData; +} +nitf_ComponentInfo; + +/*! + * Construct the component info object. We allocate a new object, + * and initialize the subheader and data sizes to zero. + * + * \param subheaderFieldWidth size of the subheader field + * \param dataFieldWidth size of data field width + * \param error error to populate on problem + * \return Return the newly created object. + */ +NITFAPI(nitf_ComponentInfo *) +nitf_ComponentInfo_construct(nitf_Uint32 subheaderFieldWidth, + nitf_Uint32 dataFieldWidth, + nitf_Error * error); + +/*! + * Clone this object. This is a deep copy operation. + * + * \param source The source object + * \param error An error to populate upon failure + * \return A new object that is identical to the old + */ +NITFAPI(nitf_ComponentInfo *) +nitf_ComponentInfo_clone(nitf_ComponentInfo * source, nitf_Error * error); + +/*! + * Destroy the image info structure and set the object to NULL. + * + * \param info This is the object to destruct and NULLify + * + */ +NITFAPI(void) nitf_ComponentInfo_destruct(nitf_ComponentInfo ** info); + + +NITF_CXX_ENDGUARD + +#endif diff --git a/modules/c/nitf/include/nitf/DESegment.h b/modules/c/nitf/include/nitf/DESegment.h new file mode 100644 index 000000000..d8aba364c --- /dev/null +++ b/modules/c/nitf/include/nitf/DESegment.h @@ -0,0 +1,75 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_DE_SEGMENT_H__ +#define __NITF_DE_SEGMENT_H__ + +#include "nitf/System.h" +#include "nitf/DESubheader.h" + + +NITF_CXX_GUARD + +/*! + * \struct nitf_DESegment + * \brief ... + * + * The DESegment object contains the sub-objects that + * make up a DES + */ +typedef struct _nitf_DESegment +{ + nitf_DESubheader *subheader; + nitf_Uint64 offset; + nitf_Uint64 end; +} +nitf_DESegment; + + +/*! + * Construct a new (empty) segment. + * + * \param error + * \return a DES + */ +NITFAPI(nitf_DESegment *) nitf_DESegment_construct(nitf_Error * error); + + +/*! + * Clone this object. This is a deep copy operation. + * + * \param source The source object + * \param error An error to populate upon failure + * \return A new object that is identical to the old + */ +NITFAPI(nitf_DESegment *) +nitf_DESegment_clone(nitf_DESegment * source, nitf_Error * error); + +/*! + * Destruct an de subheader, and NULL-set it + * \param segment A DE segment + */ +NITFAPI(void) nitf_DESegment_destruct(nitf_DESegment ** segment); + +NITF_CXX_ENDGUARD + +#endif diff --git a/modules/c/nitf/include/nitf/DESubheader.h b/modules/c/nitf/include/nitf/DESubheader.h new file mode 100644 index 000000000..14a6729cb --- /dev/null +++ b/modules/c/nitf/include/nitf/DESubheader.h @@ -0,0 +1,96 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_DE_SUBHEADER_H__ +#define __NITF_DE_SUBHEADER_H__ + +/* We get file security and some constants already */ +/* defined by including this first */ +#include "nitf/FileHeader.h" + +NITF_CXX_GUARD +#define NITF_DE_SZ 2 +#define NITF_DESTAG_SZ 25 +#define NITF_DESVER_SZ 2 +#define NITF_DESCLAS_SZ 1 +#define NITF_DESOFLW_SZ 6 +#define NITF_DESITEM_SZ 3 +#define NITF_DESSHL_SZ 4 +#define NITF_DE filePartType +#define NITF_DESTAG typeID +#define NITF_DESVER version +#define NITF_DESCLAS securityClass +#define NITF_DESOFLW overflowedHeaderType +#define NITF_DESITEM dataItemOverflowed +#define NITF_DESSHL subheaderFieldsLength + +typedef struct _nitf_DESubheader +{ + nitf_Field *filePartType; + nitf_Field *typeID; + nitf_Field *version; + nitf_Field *securityClass; + nitf_FileSecurity *securityGroup; + nitf_Field *overflowedHeaderType; + nitf_Field *dataItemOverflowed; + nitf_Field *subheaderFieldsLength; + nitf_TRE *subheaderFields; + nitf_Uint64 dataLength; + + nitf_Extensions *userDefinedSection; +} +nitf_DESubheader; + + +/*! + * Construct a new de subheader object. This object will + * be null set for every field. The object returned will be + * a full-fledged subheader, unless there is an error, in which + * case NULL will be returned, and the error object that was + * passed in will be populated. + * + * \param error In case of error, when this function returns, this + * parameter will be populated + * + * \return The de subheader, or NULL on failure. + */ +NITFAPI(nitf_DESubheader *) nitf_DESubheader_construct(nitf_Error * error); + +/*! + * TODO: Add documentation + */ +NITFAPI(nitf_DESubheader *) +nitf_DESubheader_clone(nitf_DESubheader * source, nitf_Error * error); + +/*! + * Destroy a de subheader object, and NULL-set the subheader. + * A double pointer is make the NULL-set persistant on function + * exit. + * + * \param The address of the the de subheader pointer + */ +NITFAPI(void) nitf_DESubheader_destruct(nitf_DESubheader ** subhdr); + + +NITF_CXX_ENDGUARD + +#endif diff --git a/modules/c/nitf/include/nitf/DataSource.h b/modules/c/nitf/include/nitf/DataSource.h new file mode 100644 index 000000000..1c9815c01 --- /dev/null +++ b/modules/c/nitf/include/nitf/DataSource.h @@ -0,0 +1,101 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_DATA_SOURCE_H__ +#define __NITF_DATA_SOURCE_H__ + +#include "nitf/System.h" + + +NITF_CXX_GUARD + +/* + * Function pointer for reading data (part of the data source interface) + * \param data The ancillary "helper" data + * \param buf The buffer to store the image data + * \param size The size (usually numColumns * numBytesPerPixel) + * \param error populated on error + */ +typedef NITF_BOOL(*NITF_IDATASOURCE_READ) (NITF_DATA *data, + char *buf, nitf_Off size, nitf_Error *error); + + +/* + * Function pointer for destructing the data structure (part of the data source interface) + * \param data The ancillary "helper" data + */ +typedef void (*NITF_IDATASOURCE_DESTRUCT) (NITF_DATA *); + +/*! + * Get the size of the data source + * + */ +typedef nitf_Off (*NITF_IDATASOURCE_GET_SIZE) (NITF_DATA *, nitf_Error*); + +/*! + * Set the size of the data source. (NITRO 2.0). This is useful + * when we want to stream a file into our NITF. That way our user + * does not have to write his/her own file source. + */ +typedef NITF_BOOL (*NITF_IDATASOURCE_SET_SIZE) (NITF_DATA *, + nitf_Off size, nitf_Error*); + + + +/*! + * \struct nitf_IDataSource + * \brief The data source interface + * + * This is the interface on which all of the pull-filters are + * made. + */ +typedef struct _nitf_IDataSource +{ + NITF_IDATASOURCE_READ read; + NITF_IDATASOURCE_DESTRUCT destruct; + NITF_IDATASOURCE_GET_SIZE getSize; + NITF_IDATASOURCE_SET_SIZE setSize; +} +nitf_IDataSource; + +/*! + * \struct nitf_DataSource + * \brief The "derived" data source interface + * + * This is the "derived" source. It presumes that a "constructor" + * has brought it to life. + * + */ +typedef struct _nitf_DataSource +{ + nitf_IDataSource *iface; + NITF_DATA *data; +} +nitf_DataSource; + + +NITFAPI(void) nitf_DataSource_destruct(nitf_DataSource ** dataSource); + + +NITF_CXX_ENDGUARD + +#endif diff --git a/modules/c/nitf/include/nitf/DefaultTRE.h b/modules/c/nitf/include/nitf/DefaultTRE.h new file mode 100644 index 000000000..bebee1646 --- /dev/null +++ b/modules/c/nitf/include/nitf/DefaultTRE.h @@ -0,0 +1,56 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_DEFAULT_TRE_H__ +#define __NITF_DEFAULT_TRE_H__ + +#include "nitf/System.h" +#include "nitf/TRE.h" +#include "nitf/TREUtils.h" + +NITF_CXX_GUARD + +struct _nitf_Record; +/*! + * \fn nitf_DefaultTRE_handler + * \brief The default TRE handler is what gets run if no handler + * is defined + * + * When the reader finds a TRE, it first checks the plug-in registry + * to see if it has a known plug-in handler. If not, this function + * is called instead. The default handler behavior is simply to + * store the raw data in a string in the hash table. + * + * \param io The io handle situated at the beginning of the TRE + * \param tre The tre to use + * \param error The structure to populate if an error occurs + * \return The status + * + */ +NITFAPI(nitf_TREHandler*) nitf_DefaultTRE_handler(nitf_Error * error); + + + +NITF_CXX_ENDGUARD + +#endif + diff --git a/modules/c/nitf/include/nitf/Defines.h b/modules/c/nitf/include/nitf/Defines.h new file mode 100644 index 000000000..d40335e1f --- /dev/null +++ b/modules/c/nitf/include/nitf/Defines.h @@ -0,0 +1,84 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_DEFINES_H__ +#define __NITF_DEFINES_H__ + +/* The version of the NITF library */ +#define NITF_LIB_VERSION "2.7" + +/** + * Macro which declares a TRE Plugin + * + * This assumes that the variable 'descriptions' is an accessible + * nitf_TRE_DescriptionSet + * + * _Tre the name of the input TRE + */ +#define NITF_DECLARE_PLUGIN(_Tre) \ + static const char *ident[] = { \ + NITF_PLUGIN_TRE_KEY, \ + #_Tre, \ + NULL \ + }; \ + static nitf_TREHandler _Tre##Handler; \ + NITFAPI(const char**) _Tre##_init(nitf_Error* error){ \ + if (!nitf_TREUtils_createBasicHandler(&descriptionSet,\ + &_Tre##Handler,error)) \ + return NULL; return ident; \ + } \ + NITFAPI(nitf_TREHandler*) _Tre##_handler(nitf_Error* error) { \ + (void)error; \ + return &_Tre##Handler; \ + } + +/** + * Declare a TRE Plugin with a single TREDescription + * + * _Tre the name of the input TRE + * _Description the description to use + */ +#define NITF_DECLARE_SINGLE_PLUGIN(_Tre, _Description) \ + static nitf_TREDescriptionInfo descriptions[] = { \ + { #_Tre, _Description, NITF_TRE_DESC_NO_LENGTH }, \ + { NULL, NULL, NITF_TRE_DESC_NO_LENGTH } \ + }; \ + static nitf_TREDescriptionSet descriptionSet = { 0, descriptions }; \ + NITF_DECLARE_PLUGIN(_Tre) + +/** + * Reference a TRE that has been statically compiled inside of a library + * + */ + +#ifdef __cplusplus +#define NITF_TRE_STATIC_HANDLER_REF(_Tre) \ + extern "C" char** _Tre##_init(nitf_Error*); \ + extern "C" nitf_TREHandler* _Tre##_handler(nitf_Error*); +#else +#define NITF_TRE_STATIC_HANDLER_REF(_Tre) \ + extern char** _Tre##_init(nitf_Error*); \ + extern nitf_TREHandler* _Tre##_handler(nitf_Error*); +#endif + + +#endif diff --git a/modules/c/nitf/include/nitf/DirectBlockSource.h b/modules/c/nitf/include/nitf/DirectBlockSource.h new file mode 100644 index 000000000..79e51a66f --- /dev/null +++ b/modules/c/nitf/include/nitf/DirectBlockSource.h @@ -0,0 +1,77 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2013, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +/* + \file DirectBlockSource - Band source implementation for data read directly + + The DirectBlockSource object is derived from the DataSource object and is used + in cases when the user wants to directly read blocks from file without + requiring any re-formatting or re-organization. One such case would be a file + copy. Another would be some sort of block-level data merge where data from + all sources is formatted the same. + + This allows higher performance reading and writing in such cases where the + user knows the data is formatted a certain way. +*/ + +#ifndef __NITF_DIRECT_BLOCK_SOURCE_H__ +#define __NITF_DIRECT_BLOCK_SOURCE_H__ + +#include "nitf/BandSource.h" + +NITF_CXX_GUARD + +/*! + \brief NITF_DIRECT_BLOCK_SOURCE_NEXT_BLOCK - Next row function prototype + + \param algorithm - The algorithm object + \param buf - The buffer to receive the data + \param block - The block read from file + \param blockNumber - The block number + \param blockSize - The block size + \param error - Error object for error returns + + \return Returns true on success. On failure the error object is set +*/ +typedef NITF_BOOL(*NITF_DIRECT_BLOCK_SOURCE_NEXT_BLOCK) (void *algorithm, + char * buf, + nitf_Uint8 * block, + nitf_Uint32 blockNumber, + nitf_Uint64 blockSize, + nitf_Error * error); + +/* + \brief nitf_DirectBlockSource_construct - Constructor for the DirectBlockSource + object + + \return The new object or NULL on error. On error, the error object is + set +*/ +NITFAPI(nitf_BandSource *) nitf_DirectBlockSource_construct(void * algorithm, + NITF_DIRECT_BLOCK_SOURCE_NEXT_BLOCK + nextBlock, + nitf_ImageReader* imageReader, + nitf_Uint32 numBands, + nitf_Error * error); + +NITF_CXX_ENDGUARD +#endif diff --git a/modules/c/nitf/include/nitf/DownSampler.h b/modules/c/nitf/include/nitf/DownSampler.h new file mode 100644 index 000000000..7fa0f21d0 --- /dev/null +++ b/modules/c/nitf/include/nitf/DownSampler.h @@ -0,0 +1,356 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_DOWNSAMPLER_H__ +#define __NITF_DOWNSAMPLER_H__ + + +#include "nitf/System.h" + +/*! \def NITF_PIXEL_TYPE_INT - Integer */ +# define NITF_PIXEL_TYPE_INT ((nitf_Uint32) 0x00080000) + +/*! \def NITF_PIXEL_TYPE_B - Bi-valued */ +# define NITF_PIXEL_TYPE_B ((nitf_Uint32) 0x00100000) + +/*! \def NITF_PIXEL_TYPE_SI - Two's complement signed integer */ +# define NITF_PIXEL_TYPE_SI ((nitf_Uint32) 0x00200000) + +/*! \def NITF_PIXEL_TYPE_R - Floating point */ +# define NITF_PIXEL_TYPE_R ((nitf_Uint32) 0x00400000) + +/*! \def NITF_PIXEL_TYPE_C - Complex floating point */ +# define NITF_PIXEL_TYPE_C ((nitf_Uint32) 0x00800000) + + +NITF_CXX_GUARD + +struct _nitf_DownSampler; + +/* + * This callback provides the interface for applying a sampling method while + * reading. The object argument gives access to the userData field which + * allows for customization of the available fields for this callback. + * A transformation between the input window and the output window occurs in + * this method. + * \param object The associated down-sample object + * \param inputWindows Array of input image fragments (one/band) + * \param outputWindow Array of sub-sampled image fragments (one/band) + * \param numBands Number of bands to down-sample + * \param numWindowRows How many rows for the input window + * \param numWindowCols How many cols for the input window + * \param numInputCols Number of columns in input buffer, full res + * \param numSubWindowCols The number of columns in the sub-window + * \param pixelType The pixel type (valid values found in System.h) + * \param pixelSize The size of one pixel + * \param rowsInLastWindow The number of rows in the final window + * \param colsInLastWindow The number of cols in the final window + * \param error An error to populate if something bad happened + * \return NITF_SUCCESS on success, NITF_FAILURE on failure + * + * Note: + * + * The numWindowRows, numWindowCols, and numSubWindowCols values are + * in output image units (units of sample windows). For example, with + * a pixel skip of 3 in columns, if the sub-window request spans columns + * 0-299, then numSubWindowCols is 100. If the block is such that a + * particular request spans columns 90-149 (60 full resolution columns), + * then numWindowCols is 20. The numInputCols value is in full resolution + * units. This value gives the length, in pixels of one row in the input + * buffer. This buffer is used for all down-sample calls. Since the number + * of windows can vary from call to call, this buffer has a worst case + * length. Therefore, it is not possible to move from one row to the next + * with just the number of sample windows per row (numWindowCols) for the + * current request + */ +typedef NITF_BOOL(*NITF_IDOWNSAMPLER_APPLY) (struct _nitf_DownSampler * + object, + NITF_DATA ** inputWindows, + NITF_DATA ** outputWindows, + nitf_Uint32 numBands, + nitf_Uint32 numWindowRows, + nitf_Uint32 numWindowCols, + nitf_Uint32 numInputCols, + nitf_Uint32 numSubWindowCols, + nitf_Uint32 pixelType, + nitf_Uint32 pixelSize, + nitf_Uint32 rowsInLastWindow, + nitf_Uint32 colsInLastWindow, + nitf_Error * error); + + +/*! + * Callback providing a destruct hook for derived objects. + * This method is called by nitf_DownSampler_destruct(). + * \param data The user data to delete. + */ +typedef void (*NITF_IDOWNSAMPLER_DESTRUCT) (NITF_DATA * userData); + +/*! + * \struct nitf_IDownSampler + * \brief The interface (no user data) for a downsampler + * + * This struct is usually created statically by a derived class + * constructor. It is bound to each instance of that class as + * the interface ('iface' field). + */ +typedef struct _nitf_IDownSampler +{ + NITF_IDOWNSAMPLER_APPLY apply; /* The apply method */ + NITF_IDOWNSAMPLER_DESTRUCT destruct; /* A destructor hook */ +} +nitf_IDownSampler; + + +/*! + * \struct nitf_DownSampler + * \brief The downsampler base class + * + * The downsampler base class (like the nitf_BandSource base class) + * has two components: fields or members (stored in the user data + * parameter), and a known interface of functions. This is, more or + * less, the most simplified representation of a 'class.' + * + * \param face The functional interface + * \param rowSkip The number of rows in the down-sample window + * \param colSkip The number of columns in the down-sample window + * \param multiBand The down-sampler method is muli-band + * \param minBands Minimum number of bands in multi-band method + * \param maxBands Maxmum number of bands in multi-band method + * \param types Mask of type/pixel size flags + * \param data The derived class instance data + * + * The multiBand, minBands, and maxBands fields support multi-band methods. The + * min and max fields specify required band counts. minBands is always at least + * one. For multi-band method that do not have an upper limit on badn count, + * maxBands is set to zero. + * + * The types field is a mask that specifies the supported pixel types and + * sizes. Each bit represents one type/size pair (i.e. one byte INT). For the + * binary pixel type, the byte count is one and for the 12-bit type it is two + */ + +typedef struct _nitf_DownSampler +{ + nitf_IDownSampler *iface; /* The functional interface */ + nitf_Uint32 rowSkip; /* The number of rows in the down-sample window */ + nitf_Uint32 colSkip; /* The number of cols in the down-sample window */ + NITF_BOOL multiBand; /* The down-sampler method is muli-band */ + nitf_Uint32 minBands; /* Minimum number of bands in multi-band method */ + nitf_Uint32 maxBands; /* Maxmum number of bands in multi-band method */ + nitf_Uint32 types; /* Mask of type/pixel size flags */ + NITF_DATA *data; /* To be overloaded by derived class */ +} +nitf_DownSampler; + + +/*! \def NITF_DOWNSAMPLER_TYPE_INT_1BYTE - Integer, one byte pixel */ +# define NITF_DOWNSAMPLER_TYPE_INT_1BYTE ((nitf_Uint32) 0x00000001) +/*! \def NITF_DOWNSAMPLER_TYPE_INT_2BYTE - Integer, two byte pixel */ +# define NITF_DOWNSAMPLER_TYPE_INT_2BYTE ((nitf_Uint32) 0x00000002) +/*! \def NITF_DOWNSAMPLER_TYPE_INT_4BYTE - Integer, eight byte pixel */ +# define NITF_DOWNSAMPLER_TYPE_INT_4BYTE ((nitf_Uint32) 0x00000004) +/*! \def NITF_DOWNSAMPLER_TYPE_INT_8BYTE - Integer, eight byte pixel */ +# define NITF_DOWNSAMPLER_TYPE_INT_8BYTE ((nitf_Uint32) 0x00000008) + +/*! \def NITF_DOWNSAMPLER_TYPE_B_1BYTE - Binary, one byte pixel + Note: The one bit type is presented to the user as one byte pixels +*/ +# define NITF_DOWNSAMPLER_TYPE_B_1BYTE ((nitf_Uint32) 0x00000001) + +/*! \def NITF_DOWNSAMPLER_TYPE_SI_1BYTE - Signed integer, one byte pixel */ +# define NITF_DOWNSAMPLER_TYPE_SI_1BYTE ((nitf_Uint32) 0x00000010) +/*! \def NITF_DOWNSAMPLER_TYPE_SI_2BYTE - Signed integer, two byte pixel */ +# define NITF_DOWNSAMPLER_TYPE_SI_2BYTE ((nitf_Uint32) 0x00000020) +/*! \def NITF_DOWNSAMPLER_TYPE_SI_4BYTE - Signed integer, four byte pixel */ +# define NITF_DOWNSAMPLER_TYPE_SI_4BYTE ((nitf_Uint32) 0x00000040) +/*! \def NITF_DOWNSAMPLER_TYPE_SI_8BYTE - Signed integer, eight byte pixel */ +# define NITF_DOWNSAMPLER_TYPE_SI_8BYTE ((nitf_Uint32) 0x00000080) + +/*! \def NITF_DOWNSAMPLER_TYPE_R_4BYTE - Float, four byte pixel */ +# define NITF_DOWNSAMPLER_TYPE_R_4BYTE ((nitf_Uint32) 0x00000100) +/*! \def NITF_DOWNSAMPLER_TYPE_R_8BYTE - Float, eight byte pixel */ +# define NITF_DOWNSAMPLER_TYPE_R_8BYTE ((nitf_Uint32) 0x00000200) + +/*! \def NITF_DOWNSAMPLER_TYPE_C_8BYTE - Complex, eight byte pixel */ +# define NITF_DOWNSAMPLER_TYPE_C_8BYTE ((nitf_Uint32) 0x00001000) +/*! \def NITF_DOWNSAMPLER_TYPE_C_16BYTE - Complex, sixteen byte pixel */ +# define NITF_DOWNSAMPLER_TYPE_C_16BYTE ((nitf_Uint32) 0x00002000) + +/*! \def NITF_DOWNSAMPLER_TYPE_ALL - All types */ +# define NITF_DOWNSAMPLER_TYPE_ALL \ + ( \ + NITF_DOWNSAMPLER_TYPE_INT_1BYTE | \ + NITF_DOWNSAMPLER_TYPE_INT_2BYTE | \ + NITF_DOWNSAMPLER_TYPE_INT_4BYTE | \ + NITF_DOWNSAMPLER_TYPE_INT_8BYTE | \ + NITF_DOWNSAMPLER_TYPE_B_1BYTE | \ + NITF_DOWNSAMPLER_TYPE_SI_1BYTE | \ + NITF_DOWNSAMPLER_TYPE_SI_2BYTE | \ + NITF_DOWNSAMPLER_TYPE_SI_4BYTE | \ + NITF_DOWNSAMPLER_TYPE_SI_8BYTE | \ + NITF_DOWNSAMPLER_TYPE_R_4BYTE | \ + NITF_DOWNSAMPLER_TYPE_R_8BYTE | \ + NITF_DOWNSAMPLER_TYPE_C_8BYTE | \ + NITF_DOWNSAMPLER_TYPE_C_16BYTE \ + ) + +/*! \def NITF_DOWNSAMPLER_TYPE_ALL_BUT_COMPLEX - All types except complex */ +# define NITF_DOWNSAMPLER_TYPE_ALL_BUT_COMPLEX \ + ( \ + NITF_DOWNSAMPLER_TYPE_INT_1BYTE | \ + NITF_DOWNSAMPLER_TYPE_INT_2BYTE | \ + NITF_DOWNSAMPLER_TYPE_INT_4BYTE | \ + NITF_DOWNSAMPLER_TYPE_INT_8BYTE | \ + NITF_DOWNSAMPLER_TYPE_B_1BYTE | \ + NITF_DOWNSAMPLER_TYPE_SI_1BYTE | \ + NITF_DOWNSAMPLER_TYPE_SI_2BYTE | \ + NITF_DOWNSAMPLER_TYPE_SI_4BYTE | \ + NITF_DOWNSAMPLER_TYPE_SI_8BYTE | \ + NITF_DOWNSAMPLER_TYPE_R_4BYTE | \ + NITF_DOWNSAMPLER_TYPE_R_8BYTE \ + ) + +/*! + * The pixelSkip down-sample method. This method has a designated skip + * value in the row and column, and it skips data in between. + * + * The row and column skip factors divide the sub-window into non-overlaping + * sample windows. The upper left corner pixel of each sample window is + * the down-sampled value for that window + * + * For a more comprehensive discussion of the merits and drawbacks of this + * type of down-sampling, please refer to the NITF manual 1.1. + * + * \param rowSkip The number of rows to skip + * \param colSkip The number of columns to skip + * \param error An error to populate if something bad happened + * \return This method returns an object on success, and NULL on + * failure. + */ +NITFAPI(nitf_DownSampler *) nitf_PixelSkip_construct(nitf_Uint32 rowSkip, + nitf_Uint32 colSkip, + nitf_Error * error); + + +/*! + * The maxDownSample selects the maximum pixel + * + * The row and column skip factors divide the sub-window into non-overlaping + * sample windows. The pixel with the maximum value in each sample window is + * the down-sampled value for that window. For complex images, the maximum + * the maximum absolute value (the corresponding complex value, not the + * real absolute value is the down-sample value. + * + * For a more comprehensive discussion of the merits and drawbacks of this + * type of down-sampling, please refer to the NITF manual 1.1. + * + * \param rowSkip The number of rows to skip + * \param colSkip The number of columns to skip + * \param error An error to populate if something bad happened + * \return This method returns an object on success, and NULL on + & failure. + */ +NITFAPI(nitf_DownSampler *) nitf_MaxDownSample_construct(nitf_Uint32 + rowSkip, + nitf_Uint32 + colSkip, + nitf_Error * + error); + +/*! +* \brief Sum of square, two band, down-sample method +* +* The maximum is calculated as the sum of the sum of squares of two bands. +* The caller must supply exactly two bands. The complex pixel type as the +* individual band pixel type is not supported +* +* For a more comprehensive discussion of the merits and drawbacks of this +* type of down-sampling, please refer to the NITF manual 1.1. +* +* \param rowSkip The number of rows to skip +* \param colSkip The number of columns to skip +* \param error An error to populate if something bad happened +* +* \return This method returns an object on success, and NULL on failure. +*/ + +NITFAPI(nitf_DownSampler *) nitf_SumSq2DownSample_construct(nitf_Uint32 + rowSkip, + nitf_Uint32 + colSkip, + nitf_Error * + error); + +/*! +* \brief First band select, two band, down-sample method +* +* The maximum is calculated as the value of the first band. The caller must +* supply exactly two bands. The complex pixel type as the +* individual band pixel type is not supported +* +* For a more comprehensive discussion of the merits and drawbacks of this +* type of down-sampling, please refer to the NITF manual 1.1. +* +* \param rowSkip The number of rows to skip +* \param colSkip The number of columns to skip +* \param error An error to populate if something bad happened +* +* \return This method returns an object on success, and NULL on failure. +*/ + +NITFAPI(nitf_DownSampler *) nitf_Select2DownSample_construct(nitf_Uint32 + rowSkip, + nitf_Uint32 + colSkip, + nitf_Error * + error); + +/*! + * The downsampler destructor is a management function. While it does + * free the downsampler, it first destroys any user data using the + * interface-defined hook for destruction + * + * \param downsampler The downsampler to destroy + */ +NITFAPI(void) nitf_DownSampler_destruct(nitf_DownSampler ** downsampler); + +/*! + nitf_DownSampler_apply - Apply down-sample method + + nitf_DownSampler_apply apples the down-sample method associated with + the object + + This function is implemented as a macro, see the definition for the + type NITF_IDOWNSAMPLER_APPLY +*/ + +#define nitf_DownSampler_apply(object,inputWindows,outputWindows,numBands, \ + numWindowRows,numWindowCols,numInputCols,numSubWindowCols, \ + pixelType,pixelSize,rowsInLastWindow,colsInLastWindow,error) \ +((*(object->iface->apply))(object,inputWindows,outputWindows,numBands, \ + numWindowRows,numWindowCols,numInputCols,numSubWindowCols, \ + pixelType, pixelSize,rowsInLastWindow,colsInLastWindow,error)) \ + +NITF_CXX_ENDGUARD + +#endif diff --git a/modules/c/nitf/include/nitf/Extensions.h b/modules/c/nitf/include/nitf/Extensions.h new file mode 100644 index 000000000..1941874ba --- /dev/null +++ b/modules/c/nitf/include/nitf/Extensions.h @@ -0,0 +1,264 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_EXTENSIONS_H__ +#define __NITF_EXTENSIONS_H__ + +#include "nitf/System.h" +#include "nitf/TRE.h" + +NITF_CXX_GUARD + +/*! + * \struct nitf_Extensions + * \brief Object containing listing of TREs discovered in segment + * + * The Extensions object represents the user defined and extended header + * portions of the various segments. The representation internally is + * cross-indexed -- once as an associative array, to yield fast lookups + * and once as a linked list to maintain TRE ordering. The hash table + * points at a list of TREs matching the key (which is the TRE name). + * The list is of references to the TREs containing the TRE and some + * context information. + */ +typedef struct _nitf_Extensions +{ + /* A hash of tre's (char*, [nitf_List{nitf_TRE*}]) */ + nitf_HashTable *hash; + nitf_List *ref; +} +nitf_Extensions; + + +/*! + * \struct nitf_ExtensionsIterator + * \brief The iterator defined for traversing an extension linearly + * + * The ExtensionsIterator makes use of the reference list in the Extensions + * object, in order to track a position within the extensions object + * in order. + */ +typedef struct _nitf_ExtensionsIterator +{ + nitf_ListIterator iter; +} +nitf_ExtensionsIterator; + +/*! + * Construct the extensions section. These may exist in almost + * any part of the NITF file. In essence, this object is a + * data store of information that was provided in data extensions. + * + * \param error An object to be populated on error + * \return NULL on failure, the object otherwise + * + */ +NITFAPI(nitf_Extensions *) nitf_Extensions_construct(nitf_Error * error); + +/*! + * Clone this object. This is a deep copy operation. + * + * \param source The source object + * \param error An error to populate upon failure + * \return A new object that is identical to the old + */ +NITFAPI(nitf_Extensions *) nitf_Extensions_clone(nitf_Extensions * source, + nitf_Error * error); + + + +/*! + * Destruct the extensions section. This removes the hash values + * and deletes everything. + * \param ext The address of an extensions pointer + * + */ +NITFAPI(void) nitf_Extensions_destruct(nitf_Extensions ** ext); + +/*! + * Insert a tre into the extensions section. The object will + * be added as follows. If such an object exists in the hash already, + * this object will be added to the next pointer link. + * + * 1.3 Release + * + * This function replaces the 1.2 nitf_Extensions_insert() + * There is a new nitf_Extensions_insert() function which uses + * iterators, but this appendTRE function will simply place it + * at the end + * + * \param name The name of the TRE to insert + * \param tre The tre to insert + * \return 1 on success, 0 on failure + */ +NITFAPI(NITF_BOOL) nitf_Extensions_appendTRE(nitf_Extensions * ext, + nitf_TRE * tre, + nitf_Error * error); + +/*! + * \param name The name of the TRE + * \return The TRE that is retrieved from the hash + */ +NITFAPI(nitf_List *) nitf_Extensions_getTREsByName(nitf_Extensions * ext, + const char *name); + + +/*! For backwards compatibility + * \define nitf_Extensions_get + * 1.3 mapping to 1.2 function + */ +#define nitf_Extensions_get(ext, name) nitf_Extensions_getTREsByName(ext, name) + +/*! + * This function replaces the 1.2 nitf_Extensions_erase() function, + * which was incorrectly implemented. + * + * Remove all instances of a given TRE from this extensions object. + * \param ext The name of the TRE to remove + * + */ +NITFAPI(void) nitf_Extensions_removeTREsByName(nitf_Extensions* ext, + const char* name); + +/*! + * Checks if the TRE of the given name exists + * \param name The name of the TRE + * \return 1 if exists, 0 otherwise + */ +NITFAPI(NITF_BOOL) nitf_Extensions_exists(nitf_Extensions * ext, + const char *name); + + +/*! + * The begin method produces an ExtensionsIterator that points + * at the beginning of the Extensions object. If "dereferenced," + * the iterator will produce the first TRE within the extension. + * + * \param ext The extensions segment + * \return An iterator pointing at the beginning of the extension + */ +NITFAPI(nitf_ExtensionsIterator) nitf_Extensions_begin(nitf_Extensions *ext); + +/*! + * The end method produces an ExtensionsIterator that points + * at the end of the Extensions object. If "dereferenced," + * the iterator will produce the final TRE within the extension. + * + * \param ext The extensions segment + * \return An iterator pointing at the end of the extension + */ +NITFAPI(nitf_ExtensionsIterator) nitf_Extensions_end(nitf_Extensions *ext); + +/*! + * Increments the extensions iterator + * \param extIt the iterator to increment + */ +NITFAPI(void) +nitf_ExtensionsIterator_increment(nitf_ExtensionsIterator *extIt); + +/*! + * Produce the TRE at this location ("dereference"). + * This function modified for 1.3 + * + * \param extIt The iterator + * \return The TRE that the iterator is pointing at + */ +NITFAPI(nitf_TRE *) +nitf_ExtensionsIterator_get(nitf_ExtensionsIterator *extIt); + + + +/*! + * Insert a TRE instance into the extensions location after this position + * \see nitf_List_insert + * at the iterator location. This function is new for 1.3 + * + * \param ext The name of the extensions object + * \param extIter The iterator + * \param tre The TRE to insert + * \param An error to populate on failure + * \return NITF_SUCCESS or NITF_FAILURE + */ +NITFAPI(NITF_BOOL) nitf_Extensions_insert(nitf_Extensions* ext, + nitf_ExtensionsIterator* extIter, + nitf_TRE* tre, + nitf_Error* error); + +/*! + * Remove a TRE instance at the iterator location. This function + * is new for 1.3 + * + * \param ext The name of the extensions object + * \param extIter The iterator + * \param tre The TRE to insert + * \param An error to populate on failure + * \return NITF_SUCCESS or NITF_FAILURE + */ +NITFAPI(nitf_TRE*) nitf_Extensions_remove(nitf_Extensions* ext, + nitf_ExtensionsIterator* extIter, + nitf_Error* error); + + +/*! + * Check for equality in iterators. This is typically done for + * looping purposes. + * + * \param it1 The first iterator to compare + * \param it2 The second iterator to compare + * \return True if the iterators are equal + */ +NITFAPI(NITF_BOOL) +nitf_ExtensionsIterator_equals(nitf_ExtensionsIterator *it1, + nitf_ExtensionsIterator *it2); + +/*! + * Check for inequality in iterators. This is typically done for + * conditional looping purposes. + * + * \param it1 The first iterator to compare + * \param it2 The second iterator to compare + * \return True if the iterators are not equal + */ +NITFAPI(NITF_BOOL) +nitf_ExtensionsIterator_notEqualTo(nitf_ExtensionsIterator *it1, + nitf_ExtensionsIterator *it2); + + + +/*! + * Computes the length of the extension based on its current state. + * + * This basically just adds up the lengths of all of the TREs it holds. + * + * \param ext The extension segment + * \param fver The version + * \param error The error to populate on failure + * \return the length + */ +NITFAPI(nitf_Uint32) +nitf_Extensions_computeLength(nitf_Extensions * ext, + nitf_Version fver, + nitf_Error * error); + +NITF_CXX_ENDGUARD + +#endif diff --git a/modules/c/nitf/include/nitf/Field.h b/modules/c/nitf/include/nitf/Field.h new file mode 100644 index 000000000..c20250956 --- /dev/null +++ b/modules/c/nitf/include/nitf/Field.h @@ -0,0 +1,388 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_FIELD_H__ +#define __NITF_FIELD_H__ + +#include "nitf/System.h" + +NITF_CXX_GUARD + +typedef enum _nitf_ConvType +{ + NITF_CONV_UINT, + NITF_CONV_INT, + NITF_CONV_REAL, + NITF_CONV_STRING, + NITF_CONV_RAW +} nitf_ConvType; + +#define NITF_MAX_CONV_TYPE NITF_VAL_RAW + +/* define standard lengths to use when converting */ +#define NITF_INT8_SZ 1 +#define NITF_INT16_SZ 2 +#define NITF_INT32_SZ 4 +#define NITF_INT64_SZ 8 + +/*! + * \enum FieldType + * \brief The field type describes the content of + * a field. + * + * The field type enumeration describes the possible + * content information within a field. + * + * At this point in time, we are assuming that, if it + * is BCS-A data, it is space-filled, right-aligned. + * If it is BCS-N, we expect zero-filled, left-aligned. + * If it is binary, we expect an exact fit (probably 16 or 32 bits) + */ +typedef enum _nitf_FieldType +{ + NITF_BCS_A, /* Field is basic character set alphanumeric */ + NITF_BCS_N, /* Field is basic character set numeric */ + NITF_BINARY /* Field is binary data */ +} nitf_FieldType; + +/*! + * \struct nitf_Field + * \brief Contains information corresponding to a given value + * + * The Field object contains a buffer for raw data. This data + * is *not* null-terminated, and you should not try and print it. + * It also contains a length, which the value must satisfy, in order + * to be a field. Finally, it contains a type, which is responsible + * for determining how it should compensate for the disparity between + * an actual length provided by the user, and the length that is required + */ +typedef struct _nitf_Field +{ + nitf_FieldType type; + char *raw; + size_t length; + NITF_BOOL resizable; /* private member that states whether the field + can be resized - default is false */ +} +nitf_Field; + + +/*! + * \fn nitf_Field_construct + * \param data The raw data to assign to the 'raw' field. + * \param length The length of the field. + * \param type The type of field we have (BCS-A, BCS-N, or binary) + * \param error The error to populate on failure + * \return The newly created field, or NULL on failure. + * + * Construct a new field. Return the field, unless an error occurred. + */ +NITFAPI(nitf_Field *) nitf_Field_construct(size_t length, + nitf_FieldType type, + nitf_Error * error); + + +/*! + * \fn nitf_Field_setRawData + * \param field The field to set + * \param data Any type of data, to be stored raw + * \param dataLength How long is the data to be stored (must be <= field->length) + * \param error The error to populate on miserable failure + * \return Success or failure + */ +NITFAPI(NITF_BOOL) nitf_Field_setRawData(nitf_Field * field, + NITF_DATA * data, + size_t dataLength, + nitf_Error * error); + +/*! + * \fn nitf_Field_setUint32 + * \param field The field to set + * \param number The number to set + * \param error The error to populate on miserable failure + * + * \return Success or failure + * + * The number is a unsigned 32 bit value. The number is converted to a string + * and then placed into the field according to field type. + * + * For NITF_BCS_N, the field is left padded with zeros to the correct length. + * + * For NITF_BCS_A, the field is right padded with blanks to the correct length. + * + * An error is returned if the unpadded number will not fit in the field. + * + * If field type is NITF_BCS_BINARY or an error is returned + */ + +NITFAPI(NITF_BOOL) nitf_Field_setUint32(nitf_Field * field, + nitf_Uint32 number, + nitf_Error * error); + +/*! + * \fn nitf_Field_setUint64 + * \param field The field to set + * \param number The number to set + * \param error The error to populate on miserable failure + * + * \return Success or failure + * + * The number is a unsigned 64 bit value. There are a few fields that could + * require a number outside of the 32 integer range (i.e., LIn in the file + * header). + * + * For NITF_BCS_N, the field is left padded with zeros to the correct length. + * + * For NITF_BCS_A, the field is right padded with blanks to the correct length. + * + * An error is returned if the unpadded number will not fit in the field. + * + * If field type is NITF_BCS_BINARY or an error is returned + */ + +NITFAPI(NITF_BOOL) nitf_Field_setUint64(nitf_Field * field, + nitf_Uint64 number, + nitf_Error * error); + +/*! + * \fn nitf_Field_setInt32 + * \param field The field to set + * \param number The number to set + * \param error The error to populate on miserable failure + * + * \return Success or failure + * + * The number is a signed 32 bit value. The number is converted to a string + * and then placed into the field according to field type. + * + * For NITF_BCS_N, the field is left padded with zeros to the correct length. + * + * For NITF_BCS_A, the field is right padded with blanks to the correct length. + * + * An error is returned if the unpadded number will not fit in the field. + * + * If field type is NITF_BCS_BINARY or an error is returned + */ + +NITFAPI(NITF_BOOL) nitf_Field_setInt32(nitf_Field * field, + nitf_Int32 number, + nitf_Error * error); + +/*! + * \fn nitf_Field_setInt64 + * \param field The field to set + * \param number The number to set + * \param error The error to populate on miserable failure + * + * \return Success or failure + * + * The number is a signed 64 bit value. + * + * For NITF_BCS_N, the field is left padded with zeros to the correct length. + * + * For NITF_BCS_A, the field is right padded with blanks to the correct length. + * + * An error is returned if the unpadded number will not fit in the field. + * + * If field type is NITF_BCS_BINARY or an error is returned + */ + +NITFAPI(NITF_BOOL) nitf_Field_setInt64(nitf_Field * field, + nitf_Int64 number, + nitf_Error * error); + +/*! + * \fn nitf_Field_trimString + * \param str The string to trim + * + * \return None + * + * nitf_Field_trimString is a helper fucntion that trims leading and trailing + * spaces from a string. It is intended for trimming string values returned + * from nitf_Field_get. The string must be NULL terminated. + * + * The function clears both leading and trailing spaces. + * + * A string composed entirely of blanks will become an empty string + */ + +NITFAPI(void) nitf_Field_trimString(char *str); + +/*! + * \fn nitf_Field_setString + * \param field The field to set + * \param str The string to set + * \param error The error to populate on miserable failure + * + * \return Success or failure + * + * The string should be NUL terminated. + * + * The field being set must be either NITF_BCA_A or NITF_BCA_N. + * + * If the string is not long enough it is right padded with spaces or left + * padded wit zeros, depending on the type. An error is returned if the unpadded + * string will not fit in the field. + * + */ + +NITFAPI(NITF_BOOL) nitf_Field_setString(nitf_Field * field, + const char *str, nitf_Error * error); + + +/** + * Sets the value of the field to the formatted date string, represented by + * the given DateTime and date format. + */ +NITFAPI(NITF_BOOL) nitf_Field_setDateTime(nitf_Field * field, + const nitf_DateTime *dateTime, const char *format, nitf_Error * error); + + +/*! + * \fn nitf_Field_setReal + * \param field The field to set + * \param type Conversion type character (f,e, or E) + * \param plus Include plus sign if TRUE + * \param value The value to set (a double) + * \param error The error to populate on miserable failure + * + * nitf_Field_setReal sets a real valued field to the maximum precision + * representation of the input value. Maximum precision means most decimal + * places. The result will be the sign (forcing + if requested) followed + * by the whole part with the minimum digits (atleast one) followed byt + * the decimal places and then the exponent for some types. All characters + * in the field length are used. + */ + +NITFAPI(NITF_BOOL) nitf_Field_setReal(nitf_Field * field, + const char *type, NITF_BOOL plus, + double value, nitf_Error *error); + +/*! + * \fn nitf_Field_destruct + * \param field The field to dereference, deallocate, and NULL-set + * + * Destroy the field object, and NULL-set the pointer. This is why + * we require a reference to the object pointer. + */ +NITFAPI(void) nitf_Field_destruct(nitf_Field ** field); + +/*! + * Clone this object. This is a deep copy operation. + * \todo IMPLEMENT THIS + * \param source The source object + * \param error An error to populate upon failure + * \return A new object that is identical to the old + */ +NITFAPI(nitf_Field *) nitf_Field_clone(nitf_Field * source, + nitf_Error * error); + +/*! + * \fn nitf_Field_get + * \param field The field to get + * \param outValue The output value (should be allocated already if a string) + * \param convType What to convert to + * \param length The capacity of outValue + * \param error On failure, we populate this + * \return A status + * + * \todo If length was zero, we could cast outValue to a char** and malloc it for them + * This would require that the user is smart enough to pass in an address to a char* though + * + * \todo Implement Uint stuff + * \todo Implement double and float stuff + * \todo Somebody has to ntohs() this stuff when it gets read. That should be the NITF readers + * job, since we allow users to set this internally. + * + * This method is fairly complicated. Here is what we do: + * = If the data is BCS-A||BCS-N: + * - If the user is requesting a string, the length must include the null-byte. + * - If the user is requesting a raw, the length is an actual amount to memcpy + * - If the user is requesting a 16 bit integer + * * Hurt them and then return 16 bit value + * - If the user is requesting a 32 bit integer + * * Give them back a 32 bit integer, converted using NITF_ATO32() + * - If the user is requesting a 64 bit integer + * * Give them back a 64 bit integer, converted using NITF_ATO64() + * = If the data is a binary integer + * - If the user is requesting an integer + * * Hurt them (just kidding). Make sure the internal and external sizes are same + * then give them it back in the right format + * - If the user is requesting a string + * * Allocate a 256 byte buffer, snprintf to the buffer, and give them what they are + * asking for (currently not implemented for 64 bit numbers) + * + */ +NITFAPI(NITF_BOOL) nitf_Field_get(nitf_Field * field, + NITF_DATA * outValue, + nitf_ConvType convType, + size_t length, nitf_Error * error); + +/** + * Attempt to get the Field as a DateTime object, represented by the given + * date format. + * \return a new DateTime object, which is up to the user to destroy + */ +NITFAPI(nitf_DateTime*) nitf_Field_asDateTime(nitf_Field * field, + const char* dateFormat, nitf_Error * error); + +/*! + * TODO: Add documentation + */ +NITFPROT(NITF_BOOL) nitf_Field_resetLength(nitf_Field * field, + size_t newLength, + NITF_BOOL keepData, + nitf_Error * error); + +/*! + * Print the contents of this Field + * \param field The field object + */ +NITFPROT(void) nitf_Field_print(nitf_Field * field); + + +/*! + * Resizes the field, if it is allowed to be resized. It returns false if the + * resizable member of the field is false. Otherwise, it attempts to resize + * the field, which will destroy the current raw data. + */ +NITFAPI(NITF_BOOL) nitf_Field_resizeField(nitf_Field *field, + size_t newLength, + nitf_Error *error); + +/*! + * TODO: Add documentation + */ +#define NITF_TRY_GET_UINT32(FIELD, DATA_PTR, error) \ + if (!nitf_Field_get(FIELD, DATA_PTR, NITF_CONV_UINT, NITF_INT32_SZ, error)) \ + goto CATCH_ERROR + +/*! + * TODO: Add documentation + */ +#define NITF_TRY_GET_UINT64(FIELD, DATA_PTR, error) \ + if (!nitf_Field_get(FIELD, DATA_PTR, NITF_CONV_UINT,NITF_INT64_SZ, error)) \ + goto CATCH_ERROR + +NITF_CXX_ENDGUARD + +#endif diff --git a/modules/c/nitf/include/nitf/FieldWarning.h b/modules/c/nitf/include/nitf/FieldWarning.h new file mode 100644 index 000000000..54eefb135 --- /dev/null +++ b/modules/c/nitf/include/nitf/FieldWarning.h @@ -0,0 +1,119 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_FIELD_WARNING_H__ +#define __NITF_FIELD_WARNING_H__ + +#include "nitf/System.h" +#include "nitf/Field.h" + +NITF_CXX_GUARD + + +/*! + * \struct nitf_FieldWarning + * \brief Describes a warning associated with a field in the NITF + * + * The FieldWarning object stores information necessary to describe a problem + * associated with a NITF field. + */ +typedef struct _nitf_FieldWarning +{ + /* Offset in bytes to the field in the NITF file */ + nitf_Off fileOffset; + + /* Name of the offending field in the following format + hdr.section(i). ... .fieldName + section - Any of the following section abbreviations. + If a section can occur more than once (i) + will appear where "i" is the occurance number + in the order they appear in the file + hdr - Main file header (Identification & Organization Segment) + ish(i) - ith image sub-header + imd(i) - ith image data section + gsh(i) - ith graphics sub-header + grd(i) - ith graphics data section + tsh(i) - ith text sub-header + ted(i) - ith text data section + esh(i) - ith extended data sub-header + edd(i) - ith extended data section + + (i)- ith occurance of a particular TRE in a particular + section (i.e. hdr.ish(2).ACFTB(1).SCNUM + */ + + char *fieldName; + + /* Original field found in the file */ + nitf_Field *field; + + /* Description of what was expected */ + char *expectation; + +} +nitf_FieldWarning; + + +/*! + * Construct a FieldWarning object + * This function creates a FieldWarning object. + * \param fileOffset Offset in the file to the field + * \param field A string which represents the NITF field + * \param value The NITF field value + * \param expectation A string describing the expected field value + * \param error An error object to fill if a problem occurs + * \return A FieldWarning object or NULL upon failure + */ +NITFAPI(nitf_FieldWarning *) +nitf_FieldWarning_construct(nitf_Off fileOffset, + const char *fieldName, + nitf_Field *field, + const char + *expectation, + nitf_Error * + error); + + +/*! + * Destruct a FieldWarning object + * This function destructs a FieldWarning object and NULL sets its pointer + * \param fieldWarningPtr A pointer to a FieldWarning object + */ +NITFAPI(void) nitf_FieldWarning_destruct(nitf_FieldWarning **fieldWarningPtr); + + +/*! + * Clone a FieldWarning object + * This function clones (deep copies) a FieldWarning object + * \param source The source object + * \param error An error object to fill if a problem occurs + * \return A FieldWarning object or NULL upon failure + */ +NITFAPI(nitf_FieldWarning *) nitf_FieldWarning_clone(nitf_FieldWarning *source, + nitf_Error * error); + + +/* HELP: This object should probably have 1 or more print methods, and ? */ + +NITF_CXX_ENDGUARD + +#endif diff --git a/modules/c/nitf/include/nitf/FileHeader.h b/modules/c/nitf/include/nitf/FileHeader.h new file mode 100644 index 000000000..3b64a8f20 --- /dev/null +++ b/modules/c/nitf/include/nitf/FileHeader.h @@ -0,0 +1,223 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_FILE_HEADER_H__ +#define __NITF_FILE_HEADER_H__ + +/*! + * \file + * \brief Contains the API for objects in a NITF file header + * + * This file contains the declarations for all of the objects which + * are loaded or saved during file read/write operations. + * + * + */ + +#include "nitf/System.h" +#include "nitf/FileSecurity.h" +#include "nitf/ComponentInfo.h" +#include "nitf/Extensions.h" + +#define NITF_FHDR_SZ 4 +#define NITF_FVER_SZ 5 +#define NITF_CLEVEL_SZ 2 +#define NITF_STYPE_SZ 4 +#define NITF_OSTAID_SZ 10 +#define NITF_FDT_SZ 14 +#define NITF_FTITLE_SZ 80 +#define NITF_FSCLAS_SZ 1 +#define NITF_FSCOP_SZ 5 +#define NITF_FSCPYS_SZ 5 +#define NITF_ENCRYP_SZ 1 +#define NITF_FBKGC_SZ 3 /* Nobody else is using this one! */ +#define NITF_ONAME_SZ 24 +#define NITF_OPHONE_SZ 18 +#define NITF_FL_SZ 12 +#define NITF_HL_SZ 6 + +#define NITF_LISH_SZ 6 +#define NITF_LI_SZ 10 +#define NITF_LSSH_SZ 4 +#define NITF_LS_SZ 6 +#define NITF_LLSH_SZ 4 +#define NITF_LL_SZ 3 +#define NITF_LTSH_SZ 4 +#define NITF_LT_SZ 5 +#define NITF_LDSH_SZ 4 +#define NITF_LD_SZ 9 +#define NITF_LRESH_SZ 4 +#define NITF_LRE_SZ 7 +/* This is the tricky part... */ +#define NITF_UDHDL_SZ 5 +#define NITF_UDHOFL_SZ 3 +#define NITF_XHDL_SZ 5 +#define NITF_XHDLOFL_SZ 3 + +/* new ones added by TZ */ +#define NITF_NUMI_SZ 3 +#define NITF_NUMS_SZ 3 +#define NITF_NUMX_SZ 3 +#define NITF_NUMT_SZ 3 +#define NITF_NUMDES_SZ 3 +#define NITF_NUMRES_SZ 3 + + +#define NITF_FHDR fileHeader +#define NITF_FVER fileVersion +#define NITF_CLEVEL complianceLevel +#define NITF_STYPE systemType +#define NITF_OSTAID originStationID +#define NITF_FDT fileDateTime +#define NITF_FTITLE fileTitle +#define NITF_FSCLAS classification +#define NITF_FSCOP messageCopyNum +#define NITF_FSCPYS messageNumCopies +#define NITF_ENCRYP encrypted +#define NITF_FBKGC backgroundColor +#define NITF_ONAME originatorName +#define NITF_OPHONE originatorPhone +#define NITF_FL fileLength +#define NITF_HL headerLength +#define NITF_LISH(i) imageInfo[i]->lengthSubheader +#define NITF_LI(i) imageInfo[i]->lengthData +#define NITF_LSSH(i) graphicInfo[i]->lengthSubheader +#define NITF_LS(i) graphicInfo[i]->lengthData +#define NITF_LLSH(i) labelInfo[i]->lengthSubheader +#define NITF_LL(i) labelInfo[i]->lengthData +#define NITF_LTSH(i) textInfo[i]->lengthSubheader +#define NITF_LT(i) textInfo[i]->lengthData +#define NITF_LDSH(i) dataExtensionInfo[i]->lengthSubheader +#define NITF_LD(i) dataExtensionInfo[i]->lengthData +#define NITF_LRESH(i) reservedExtensionInfo[i]->lengthSubheader +#define NITF_LRE(i) reservedExtensionInfo[i]->lengthData + +#define NITF_NUMI numImages +#define NITF_NUMS numGraphics +#define NITF_NUMX numLabels +#define NITF_NUMT numTexts +#define NITF_NUMDES numDataExtensions +#define NITF_NUMRES numReservedExtensions + +#define NITF_UDHDL userDefinedHeaderLength +#define NITF_UDHOFL userDefinedOverflow +#define NITF_XHDL extendedHeaderLength +#define NITF_XHDLOFL extendedHeaderOverflow + +NITF_CXX_GUARD + +/*! + * \struct nitf_FileHeader + * \brief A structure representing the in-memory layout of the NITF file + * + * This object is the in-core representation of an NITF file header + * its accessor fields may be called by their longnames (the manner in + * which they are declared) or by their 'nicknames,' which are provided + * above. The shortcuts are also for algorithmically determining a length + * given only the name, using the construction {SHORTNAME}##SZ + * + */ +typedef struct _nitf_FileHeader +{ + nitf_Field *fileHeader; + nitf_Field *fileVersion; + nitf_Field *complianceLevel; + nitf_Field *systemType; + nitf_Field *originStationID; + nitf_Field *fileDateTime; + nitf_Field *fileTitle; + nitf_Field *classification; + + nitf_FileSecurity *securityGroup; + + nitf_Field *messageCopyNum; + nitf_Field *messageNumCopies; + nitf_Field *encrypted; + nitf_Field *backgroundColor; + nitf_Field *originatorName; + nitf_Field *originatorPhone; + + nitf_Field *fileLength; + nitf_Field *headerLength; + + nitf_Field *numImages; + nitf_Field *numGraphics; + nitf_Field *numLabels; + nitf_Field *numTexts; + nitf_Field *numDataExtensions; + nitf_Field *numReservedExtensions; + + nitf_ComponentInfo **imageInfo; + nitf_ComponentInfo **graphicInfo; + nitf_ComponentInfo **labelInfo; + nitf_ComponentInfo **textInfo; + nitf_ComponentInfo **dataExtensionInfo; + nitf_ComponentInfo **reservedExtensionInfo; + + nitf_Field *userDefinedHeaderLength; + nitf_Field *userDefinedOverflow; + nitf_Field *extendedHeaderLength; + nitf_Field *extendedHeaderOverflow; + + nitf_Extensions *userDefinedSection; + nitf_Extensions *extendedSection; + /* udhdl, udhofl, udhd */ + /* xhdl, xhdlofl, xhd */ + +} +nitf_FileHeader; + +/*! + * We want to construct and init the whole object. + * We NULL-initialize all sub-objects before creating them, so that, + * in the event of an exception, memory deallocation is easier. + * This is tedious, but prevents bug-prone problems + * + * \param error An error to populate on a NULL return + * \return The newly allocated file header, or NULL upon failure + * + */ +NITFAPI(nitf_FileHeader *) nitf_FileHeader_construct(nitf_Error * error); + + +/*! + * Clone this object. This is a deep copy operation. + * + * \param source The source object + * \param error An error to populate upon failure + * \return A new object that is identical to the old + */ +NITFAPI(nitf_FileHeader *) nitf_FileHeader_clone(nitf_FileHeader * source, + nitf_Error * error); + +/*! + * Destruct all sub-objects, and make sure that we + * kill this object too. + * + * \param fh The file header to destroy. We point fh at NULL. + */ +NITFAPI(void) nitf_FileHeader_destruct(nitf_FileHeader ** fh); + + +NITF_CXX_ENDGUARD + +#endif diff --git a/modules/c/nitf/include/nitf/FileSecurity.h b/modules/c/nitf/include/nitf/FileSecurity.h new file mode 100644 index 000000000..347405079 --- /dev/null +++ b/modules/c/nitf/include/nitf/FileSecurity.h @@ -0,0 +1,206 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_FILE_SECURITY_H__ +#define __NITF_FILE_SECURITY_H__ + + +/*! + * \file + * \brief Handle the file security groupings that appear throughout + * + * Any of the headers or subheaders have security groupings. The + * object declared in this header is the storage container for such + * information + * + */ + +#include "nitf/System.h" +#include "nitf/Field.h" + +/* + * The constants below define the lengths of each field contained in + * the security info in any header for a NITF file + * + */ + +/* + * These are the constant lengths for the 2.1 FileSecurity fields + */ +#define NITF_CLSY_SZ 2 +#define NITF_CODE_SZ 11 +#define NITF_CTLH_SZ 2 +#define NITF_REL_SZ 20 +#define NITF_DCTP_SZ 2 +#define NITF_DCDT_SZ 8 +#define NITF_DCXM_SZ 4 +#define NITF_DG_SZ 1 +#define NITF_DGDT_SZ 8 +#define NITF_CLTX_SZ 43 +#define NITF_CATP_SZ 1 +#define NITF_CAUT_SZ 40 +#define NITF_CRSN_SZ 1 +#define NITF_RDT_SZ 8 +#define NITF_CTLN_SZ 15 + +/* + * The total block size for a 2.1 FileSecurity section + */ +#define NITF_SG_BLOCK_SZ \ + NITF_CLSY_SZ + \ + NITF_CODE_SZ + \ + NITF_CTLH_SZ + \ + NITF_REL_SZ + \ + NITF_DCTP_SZ + \ + NITF_DCDT_SZ + \ + NITF_DCXM_SZ + \ + NITF_DG_SZ + \ + NITF_DGDT_SZ + \ + NITF_CLTX_SZ + \ + NITF_CATP_SZ + \ + NITF_CAUT_SZ + \ + NITF_CRSN_SZ + \ + NITF_RDT_SZ + \ + NITF_CTLN_SZ + +/* + * These are the constant lengths for the 2.0 FileSecurity fields + * Notice that there are less fields in 2.0 than in 2.1... + */ +#define NITF_CODE_20_SZ 40 +#define NITF_CTLH_20_SZ 40 +#define NITF_REL_20_SZ 40 +#define NITF_CAUT_20_SZ 20 +#define NITF_CTLN_20_SZ 20 +#define NITF_DGDT_20_SZ 6 +#define NITF_CLTX_20_SZ 40 + + +/* + * It is suitable to refer to the object field either by its meaningful + * name, or by its specification name. The short (spec) names are just + * aliases to the full names. They also help us internally to perform + * macros which require that the length field can be algorithmically + * constructed using the form {SHORTNAME}##SZ + * + */ + +#define NITF_CLSY classificationSystem +#define NITF_CODE codewords +#define NITF_CTLH controlAndHandling +#define NITF_REL releasingInstructions +#define NITF_DCTP declassificationType +#define NITF_DCDT declassificationDate +#define NITF_DCXM declassificationExemption +#define NITF_DG downgrade +#define NITF_DGDT downgradeDateTime +#define NITF_CLTX classificationText +#define NITF_CATP classificationAuthorityType +#define NITF_CAUT classificationAuthority +#define NITF_CRSN classificationReason +#define NITF_RDT securitySourceDate +#define NITF_CTLN securityControlNumber + +NITF_CXX_GUARD + +/*! + * \struct nitf_FileSecurity + * \brief This class keeps track of the file security info + * + * The file security struct has a number of fields pertaining + * to security information from the nitf file. You may access these + * by their longnames, as they are declared, or you may use the shorthand + * macros provided above + * + */ +typedef struct _nitf_FileSecurity +{ + + nitf_Field *classificationSystem; + nitf_Field *codewords; + nitf_Field *controlAndHandling; + nitf_Field *releasingInstructions; + nitf_Field *declassificationType; + nitf_Field *declassificationDate; + nitf_Field *declassificationExemption; + nitf_Field *downgrade; + nitf_Field *downgradeDateTime; + nitf_Field *classificationText; + nitf_Field *classificationAuthorityType; + nitf_Field *classificationAuthority; + nitf_Field *classificationReason; + nitf_Field *securitySourceDate; + nitf_Field *securityControlNumber; + +} +nitf_FileSecurity; + +/*! + * Create this object and memset components to zero. + * + * \param error An error to populate on a NULL return + * \return the object + */ +NITFAPI(nitf_FileSecurity *) nitf_FileSecurity_construct(nitf_Error * + error); + +/*! + * Clone this object. This is a deep copy operation. + * + * \param source The source object + * \param error An error to populate upon failure + * \return A new object that is identical to the old + */ +NITFAPI(nitf_FileSecurity *) nitf_FileSecurity_clone(nitf_FileSecurity * + source, + nitf_Error * error); + + +/*! + * Delete this object and null it. + * \param fs The file security object + */ +NITFAPI(void) nitf_FileSecurity_destruct(nitf_FileSecurity ** fs); + + +/*! + * Resizes the FileSecurity fields that are different sizes between + * different versions of the NITF specification. Calling with a valid + * nitf_Version will resize for that version. The default is to size + * for NITF 2.1 (NITF_VER_21) + * + * \param fs The source object + * \param ver The nitf_Version to use + * \param error An error to populate upon failure + * \return NITF_SUCCESS if valid, NITF_FAILURE otherwise + */ +NITFAPI(NITF_BOOL) nitf_FileSecurity_resizeForVersion +( + nitf_FileSecurity *fs, + nitf_Version ver, + nitf_Error * error +); + + +NITF_CXX_ENDGUARD + +#endif diff --git a/modules/c/nitf/include/nitf/GraphicSegment.h b/modules/c/nitf/include/nitf/GraphicSegment.h new file mode 100644 index 000000000..9544fe311 --- /dev/null +++ b/modules/c/nitf/include/nitf/GraphicSegment.h @@ -0,0 +1,79 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_GRAPHIC_SEGMENT_H__ +#define __NITF_GRAPHIC_SEGMENT_H__ + +#include "nitf/System.h" +#include "nitf/GraphicSubheader.h" + + +NITF_CXX_GUARD + +/*! + * \struct nitf_GraphicSegment + * \brief ... + * + * The GraphicSegment object contains the sub-objects that + * ... + */ +typedef struct _nitf_GraphicSegment +{ + nitf_GraphicSubheader *subheader; + nitf_Uint64 offset; + nitf_Uint64 end; + char *graphic; +} +nitf_GraphicSegment; + + +/*! + * Construct a new header. This simply produces an empty + * subheader + * + * \param error + * \return A graphic header + */ +NITFAPI(nitf_GraphicSegment *) +nitf_GraphicSegment_construct(nitf_Error * error); + + +/*! + * Clone this object. This is a deep copy operation. + * + * \param source The source object + * \param error An error to populate upon failure + * \return A new object that is identical to the old + */ +NITFAPI(nitf_GraphicSegment *) +nitf_GraphicSegment_clone(nitf_GraphicSegment * source, + nitf_Error * error); + +/*! + * Destruct a graphic subheader, and NULL-set it + * \param segment A graphic segment + */ +NITFAPI(void) nitf_GraphicSegment_destruct(nitf_GraphicSegment ** segment); + +NITF_CXX_ENDGUARD + +#endif diff --git a/modules/c/nitf/include/nitf/GraphicSubheader.h b/modules/c/nitf/include/nitf/GraphicSubheader.h new file mode 100644 index 000000000..1d2f59828 --- /dev/null +++ b/modules/c/nitf/include/nitf/GraphicSubheader.h @@ -0,0 +1,129 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_GRAPHIC_SUBHEADER_H__ +#define __NITF_GRAPHIC_SUBHEADER_H__ + +/* We get file security and some constants already */ +/* defined by including this first */ +#include "nitf/FileHeader.h" + +#define NITF_SY_SZ 2 +#define NITF_SID_SZ 10 +#define NITF_SNAME_SZ 20 +#define NITF_SSCLAS_SZ 1 +#define NITF_SFMT_SZ 1 +#define NITF_SSTRUCT_SZ 13 +#define NITF_SDLVL_SZ 3 +#define NITF_SALVL_SZ 3 +#define NITF_SLOC_SZ 10 +#define NITF_SBND1_SZ 10 +#define NITF_SCOLOR_SZ 1 +#define NITF_SBND2_SZ 10 +#define NITF_SRES2_SZ 2 +#define NITF_SY filePartType +#define NITF_SID graphicID +#define NITF_SNAME name +#define NITF_SSCLAS securityClass +#define NITF_SFMT stype +#define NITF_SSTRUCT res1 +#define NITF_SDLVL displayLevel +#define NITF_SALVL attachmentLevel +#define NITF_SLOC location +#define NITF_SBND1 bound1Loc +#define NITF_SCOLOR color +#define NITF_SBND2 bound2Loc +#define NITF_SRES2 res2 +#define NITF_SXSHDL_SZ 5 +#define NITF_SXSOFL_SZ 3 +#define NITF_SXSHDL extendedHeaderLength +#define NITF_SXSOFL extendedHeaderOverflow + +NITF_CXX_GUARD + +/*! + * TODO: Add documentation + */ +typedef struct _nitf_GraphicSubheader +{ + nitf_Field *filePartType; + nitf_Field *graphicID; + nitf_Field *name; + nitf_Field *securityClass; + nitf_FileSecurity *securityGroup; + nitf_Field *encrypted; + nitf_Field *stype; + nitf_Field *res1; + nitf_Field *displayLevel; + nitf_Field *attachmentLevel; + nitf_Field *location; + nitf_Field *bound1Loc; + nitf_Field *color; + nitf_Field *bound2Loc; + nitf_Field *res2; + + nitf_Field *extendedHeaderLength; + nitf_Field *extendedHeaderOverflow; + + /* This section (unfortunately), has an extendedSection */ + nitf_Extensions *extendedSection; + +} +nitf_GraphicSubheader; + + +/*! + * Construct a new graphic subheader object. This object will + * be null set for every field. The object returned will be + * a full-fledged subheader, unless there is an error, in which + * case NULL will be returned, and the error object that was + * passed in will be populated. + * + * \param error In case of error, when this function returns, this + * parameter will be populated + * + * \return The graphic subheader, or NULL on failure. + */ +NITFAPI(nitf_GraphicSubheader *) +nitf_GraphicSubheader_construct(nitf_Error * error); + +/*! + * TODO: Add documentation + */ +NITFAPI(nitf_GraphicSubheader *) +nitf_GraphicSubheader_clone(nitf_GraphicSubheader * source, + nitf_Error * error); + +/*! + * Destroy a graphic subheader object, and NULL-set the subheader. + * A double pointer is make the NULL-set persistant on function + * exit. + * + * \param The address of the the graphic subheader pointer + */ +NITFAPI(void) nitf_GraphicSubheader_destruct(nitf_GraphicSubheader ** + subhdr); + + +NITF_CXX_ENDGUARD + +#endif diff --git a/modules/c/nitf/include/nitf/ImageIO.h b/modules/c/nitf/include/nitf/ImageIO.h new file mode 100644 index 000000000..9cfde9ea6 --- /dev/null +++ b/modules/c/nitf/include/nitf/ImageIO.h @@ -0,0 +1,929 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +/*! + \file + \brief NITF Image segment image data I/O object (nitf_ImageIO) + + \todo Implement deep copy clone + The nitf_ImageIO object is used to manage the pixel data I/O for one image + segment of a NITF image. + + The pixel type constants are needed for an argument of the down-sample + plug-in functions. Their odd encoding is because they are used internally + as part of a mask that contains other private bit definitions. +*/ + +#ifndef NITF_IMAGE_IO_INCLUDED +#define NITF_IMAGE_IO_INCLUDED + +#include "nitf/System.h" +#include "nitf/PluginIdentifier.h" +#include "nitf/ImageSubheader.h" +#include "nitf/SubWindow.h" + +/*! \def NITF_IMAGE_IO_NO_OFFSET - No block/mask offset */ + +#define NITF_IMAGE_IO_NO_OFFSET ((nitf_Uint32) 0xffffffff) + +/*! \def NITF_NBPP_TO_BYTES - Compute bytes per pixel from NBPP field */ + +#define NITF_NBPP_TO_BYTES(nbpp) ((((int) (nbpp)) - 1)/8 + 1) + +/*! \def NITF_IMAGE_IO_PIXEL_TYPE_INT - Integer */ +#define NITF_IMAGE_IO_PIXEL_TYPE_INT ((nitf_Uint32) 0x00080000) + +/*! \def NITF_IMAGE_IO_PIXEL_TYPE_B - Bi-valued */ +#define NITF_IMAGE_IO_PIXEL_TYPE_B ((nitf_Uint32) 0x00100000) + +/*! \def NITF_IMAGE_IO_PIXEL_TYPE_SI - Two's complement signed integer */ +#define NITF_IMAGE_IO_PIXEL_TYPE_SI ((nitf_Uint32) 0x00200000) + +/*! \def NITF_IMAGE_IO_PIXEL_TYPE_R - Floating point */ +#define NITF_IMAGE_IO_PIXEL_TYPE_R ((nitf_Uint32) 0x00400000) + +/*! \def NITF_IMAGE_IO_PIXEL_TYPE_C - Complex floating point */ +#define NITF_IMAGE_IO_PIXEL_TYPE_C ((nitf_Uint32) 0x00800000) + +/* Psuedo type for 12 bit integer (NBPP == 12 and ABPP = 12) */ +/*! \def NITF_IMAGE_IO_PIXEL_TYPE_12 - 12 bit integer signed or unsigned */ +#define NITF_IMAGE_IO_PIXEL_TYPE_12 ((nitf_Uint32) 0x01000000) + +NITF_CXX_GUARD + +/*! + \brief NITF Image segment image data I/O object handle + + The \b nitf_ImageIO is the object used to manage one the image data I/O for + one image segment of one image. There are no user accessible fields + +*/ +typedef void nitf_ImageIO; + +/*! + \brief nitf_BlockingInfo - Blocking information structure + + The \b nitf_BlockingInfo provides information about an image segment's block + organization. This structure is obtained by calling the function + \b nitf_ImageIO_getBlockingInfo. The information in this structure reflects + the correct information. Due to the implementation of some compression + types the information in the image segment header may not be correct. + +*/ + +typedef struct _nitf_BlockingInfo +{ + nitf_Uint32 numBlocksPerRow; /*!< Number of blocks per row */ + nitf_Uint32 numBlocksPerCol; /*!< Number of blocks per column */ + nitf_Uint32 numRowsPerBlock; /*!< Number of rows per block */ + nitf_Uint32 numColsPerBlock; /*!< Number of columns per block */ + size_t length; /*!< Total block length in bytes */ +} +nitf_BlockingInfo; + + +/*! + \brief Constructor for the nitf_BlockingInfo object + + \b nitf_BlockingInfo_construct is the constructor for the \em nitf_BlockingInfo object. + The returned object must be freed via the object's destructor, + \em nitf_BlockingInfo_destruct + + \return The new object or NULL on error + + On error, the user supplied error object is set. Possible errors include: + + Memory allocation error\n +*/ +NITFPROT(nitf_BlockingInfo *) nitf_BlockingInfo_construct(nitf_Error * + error); + +/*! + \brief Destructor for the nitf_BlockingInfo object + + \b nitf_BlockingInfo_destruct deallocates the memory associated with the object. + The argument is set to NULL on return + + \return None +*/ +NITFPROT(void) nitf_BlockingInfo_destruct(nitf_BlockingInfo ** info); + + +/*! + \brief nitf_ImageIO_writeSequential - Create write control object for + sequential writing full rows, all bands + + nitf_ImageIO_writeSequential creates a write control object for sequential + writes of full rows with all bands. + + The caller supplied IO handle is retained internally. The subsequent write + operations position the handle to the correct location before writing. The + handle is not repositioned after the operation. The caller can use the handle + between write calls but must not close or destroy it. The write done function + does not close the handle. + + State information about the write operation is mantained in the image I/O + object. It is an error to try to start another operation before the write + done function is called. + + \param nitf Associated ImageIO object + \param io The IO interface to use + \param error [out] return errors + \return FALSE is returned on error and the error object is set + + Possible errors: + + Write already in progress + Memory allocation errors + I/O errors + +*/ + +NITFPROT(NITF_BOOL) nitf_ImageIO_writeSequential(nitf_ImageIO * nitf, + nitf_IOInterface* io, + nitf_Error * error + ); + +/*! + \brief nitf_ImageIO_writeDone - Cleanup for write + + nitf_ImageIOWrite_writeDone does post writing clean-up for the calling + object. + + All memory allocated for the write operation is freed and any deferred write + operations are complete. The deferred writes are done by calling the flush + operation. + + \param object Object to cleanup + \param io io interface to use + \param error [out] The error to return + + \return One error, FALSE is returned and the caller supplied error object + is set. + + Possible errors: + + Writer not active + I/O errors + Memory allocation errors + Invalid row count + +*/ + +NITFPROT(NITF_BOOL) nitf_ImageIO_writeDone(nitf_ImageIO * object, + nitf_IOInterface* io, + nitf_Error * error); + +/*! + \brief nitf_ImageIO_writeRows - Write rows more rows + + nitf_ImageIO_writeRows writes consecutive rows to the image. The rows + are written after the rows of the previous call. This function is for + sequential writes of complete rows + + The "data" argument is an array of pointers. Each pointer points to the + row data for one band. When multiple rows are written (numRows != 1), + Each pointer points to numRows rows of data for that band. The pointers + should be ordered according to the band order. + + The image I/O object must be set-up for write by one of the following + functions: + + nitf_ImageIO_writeSequential + + \param object Associated ImageIO object + \param io Interface for writes + \param data Row buffers, one per band + \param erro For error reports + \return One error, FALSE is returned and the caller supplied error object + is set. + + Possible errors: + + Writer not active + I/O errors + Memory allocation errors + Invalid row count +*/ + +NITFPROT(NITF_BOOL) nitf_ImageIO_writeRows(nitf_ImageIO * object, + nitf_IOInterface* io, + nitf_Uint32 numRows, + nitf_Uint8 ** data, + nitf_Error * error + ); + +/*! + \brief nitf_ImageIO_flush - Complete deferred writes + + nitf_ImageIO_flush completes any deferred write associated with the + calling object. An example of something that might be deferred is the + writing of the block mask. + + \param The object to flush + \param io The interface pointer + \param error [out] error to return + \return On error, FALSE is returned and the supplied error object is set + + Possible errors include: + + Writer not active + I/O errors +*/ + +NITFPROT(NITF_BOOL) nitf_ImageIO_flush(nitf_ImageIO * object, + nitf_IOInterface* io, + nitf_Error * error + ); + + +/*! + \brief nitf_ImageIO_setPadPixel - Set the pad pixel value used for write + + nitf_ImageIO_setPadPixel sets the pad pixel value used for write. This + value is used for write operations. + + If after this call, the image object is used for a read and the image + segment defines a pad pixel value. The value is set to the segment's + value + + Because the pad pixel's type depends on the pixel type the user must give + the value as a byte pointer and length. + \param object to flush + \param pad pixel value + \param length of the value + \return None + +*/ + +NITFPROT(NITF_BOOL) +nitf_ImageIO_setPadPixel(nitf_ImageIO * object, + nitf_Uint8 * value, + nitf_Uint32 length, + nitf_Error* error + ); + + +/*! + \brief nitf_CompressionControl - Compression control object + + The nitf_CompressionControl object manages the writing of blocks for + one image segment. The use of this object is not thread safe but the + reader objects that are created from it are thread safe if thread safe + operations are supported. + + The object has no public fields and may be different for each compression + library +*/ + +typedef void nitf_CompressionControl; + +/*! + \brief NITF_COMPRESSION_INTERFACE_OPEN_FUNCTION - Image compression + interface open function + + This function pointer type is the type for the open field in the + compression interface object. The function creates the interface control + object and extracts any required values from the supplied image sub-header + + The plugin object should not retain a reference to the subheader object. + + The plugin may modify subheader values to be consistent with the compression + type's BIIF specification. For example a required block size. It may also + generate an error if some subheader fields are not the required values. + + \ar subheader - Associated image subheader + \ar options - Compression options. May be NULL. + \ar error - Error object + + \return The new nitf_CompressionControl structure or NULL on error +*/ + +typedef nitf_CompressionControl * +(*NITF_COMPRESSION_INTERFACE_OPEN_FUNCTION) + (nitf_ImageSubheader * subheader, + nrt_HashTable* options, nitf_Error * error); + +/*! + \brief NITF_COMPRESSION_INTERFACE_START_FUNCTION - Image compression + interface start function + + This function pointer type is the type for the start field in the + compression interface object. The function initializes the compression + + \ar object - The compression control from the open function + \ar offset - File offset to start of compressed data output + \ar dataLength - Length of uncompressed data + \ar blockMask - Block mask, possibly updated during compression + \ar padMask - Pad mask, possibly updated during compression + \ar error - Error object + + \return True on success and false on error + + The mask may be updated as the blocks are written by the write block + function or after compression is complete by the end function. Copies + of the pointers are maintained internally. If the masks are NULL, then + the compression type is unmasked (i.e., C3 v M3) + + In order to avoid major complicated logic in the main library, the start + function is responsible for verifying any plugin specific requirements such + as allowed pixel size and type + + The plugin may retain the mask pointers and the IO interface supplied to the + write block function + + On error, the error object is set +*/ + +typedef NITF_BOOL +(*NITF_COMPRESSION_INTERFACE_START_FUNCTION) +(nitf_CompressionControl *object, + nitf_Uint64 offset,nitf_Uint64 dataLength, + nitf_Uint64 * blockMask, + nitf_Uint64 * padMask, nitf_Error * error); + +/*! + \brief NITF_COMPRESSION_INTERFACE_WRITE_BLOCK_FUNCTION - Image + compression interface write block function + + This function pointer type is the type for the writeBlock field in the + compression interface object. The function writes a block. + + The data is supplied to the compressor in order, starting with the first + block. If pad is true, then the block contains pad pixels. If noData is true, + then this is a pad-only,missing block. The compression type may or may not + support missing blocks. + + \ar object - Associated compression control + \ar handle - The IO handle for image IO + \ar data - Block data + \ar NITF_BOOL pad - Block contains some pad block + \ar NITF_BOOL noData - Block has no data (pad only) + \ar error - Error object + + \return Error flag, false means error + +*/ + +typedef NITF_BOOL (*NITF_COMPRESSION_INTERFACE_WRITE_BLOCK_FUNCTION) +(nitf_CompressionControl * object, nitf_IOInterface* io,const nitf_Uint8 *data, + NITF_BOOL pad,NITF_BOOL noData,nitf_Error *error); + +/*! + \brief NITF_COMPRESSION_INTERFACE_END_FUNCTION - Image compression + interface end function + + This function pointer type is the type for the end field in the + compression interface object. The function completes the writing of + the compressed data and makes any final changes to the block masks + + \ar object - Associated compression control + \ar handle - The IO handle for image IO + \ar error - Error object + + \return Error flag, false means error + +*/ + +typedef NITF_BOOL (*NITF_COMPRESSION_INTERFACE_END_FUNCTION) +(nitf_CompressionControl * object,nitf_IOInterface* io,nitf_Error *error); + +/*! + \brief NITF_COMPRESSION_CONTROL_DESTROY_FUNCTION - Image compression + interface control object destructor + + This function pointer type is the type for the destroy field in the + compression interface object. The function destroys a interface control + object. + + \ar object - Associated interface control + + \return none + + On error, the error object is set +*/ + +typedef void (*NITF_COMPRESSION_CONTROL_DESTROY_FUNCTION) +(nitf_CompressionControl ** object); + + +/*! + \brief nitf_DecompressionControl - Decompression control object + + The nitf_DecompressionControl object manages the reading of blocks for + one image segment. The use of this object is not thread safe but the + reader objects that are created from it are thread safe if thread safe + operations are supported. + + The object has no public fields and may be different for each compression + library +*/ + +typedef void nitf_DecompressionControl; + +/*! + \brief NITF_DECOMPRESSION_INTERFACE_OPEN_FUNCTION - Image decompression + interface open function. This creates and prepares the decompressor for + first image data access. + + \ar subheader - Associated image subheader + \ar options - Decompression options. May be NULL. Not needed + for most decompressors + \ar error - Error object + + \return The new nitf_DecompressionControl structure or NULL on error +*/ + +typedef nitf_DecompressionControl * +(*NITF_DECOMPRESSION_INTERFACE_OPEN_FUNCTION) +(nitf_ImageSubheader * subheader, + nrt_HashTable* options, nitf_Error * error); + +/*! + \brief NITF_DECOMPRESSION_INTERFACE_START_FUNCTION - Image decompression + interface start function + + This function pointer type is the type for the open field in the + decompression interface object. + + \ar object - The decompression object + \ar io - The IO interface for image IO + \ar offset - File offset to start of compressed data + \ar fileLength - Length of compressed data in the file + \ar blockingDefinition - Blocking information for the image + \ar blockMask - Block mask + \ar error - Error object + + \return On error, FALSE is returned + + On error, the error object is set +*/ + +typedef NITF_BOOL +(*NITF_DECOMPRESSION_INTERFACE_START_FUNCTION) +(nitf_DecompressionControl *object, + nitf_IOInterface* io, + nitf_Uint64 offset, + nitf_Uint64 fileLength, + nitf_BlockingInfo * blockingDefinition, + nitf_Uint64 * blockMask, nitf_Error * error); + + /*! + \brief NITF_DECOMPRESSION_INTERFACE_READ_BLOCK_FUNCTION - Image + decompression interface read block function + + This function pointer type is the type for the readBlock field in the + decompression interface object. The function reads a block. + + The reader allocates the returned buffer which may be obtained by some + facility other than the NITF library memory allocation interface. This + buffer must be freed via the freeBlock function entry. + + \ar object - Associated reader + \ar blockNumber - Block number + \ar error - Error object + + \return The data in a buffer or NULL on error + + On error, the error object is set +*/ + +typedef nitf_Uint8 *(*NITF_DECOMPRESSION_INTERFACE_READ_BLOCK_FUNCTION) +(nitf_DecompressionControl * object, + nitf_Uint32 blockNumber, nitf_Uint64* blockSize, nitf_Error * error); + +/*! + \brief NITF_DECOMPRESSION_INTERFACE_FREE_BLOCK_FUNCTION - Image + decompression interface free block function + + This function pointer type is the type for the freeBlock field in the + decompression interface object. The function frees a block allocated by + the reader. + + \ar object - Associated reader + \ar block - Block to free + \ar error - Error object + + \return On error, FALSE is returned + + On error, the error object is set +*/ + +typedef NITF_BOOL(*NITF_DECOMPRESSION_INTERFACE_FREE_BLOCK_FUNCTION) +(nitf_DecompressionControl * object, + nitf_Uint8 * block, nitf_Error * error); + +/*! + \brief NITF_DECOMPRESSION_CONTROL_DESTROY_FUNCTION - Image decompression + interface control object destructor + + This function pointer type is the type for the destroy field in the + decompression interface object. The function destroys a interface control + object. + + \ar object - Associated interface control + \ar error - Error object + + \return On error, FALSE is returned + + On error, the error object is set +*/ + +typedef void (*NITF_DECOMPRESSION_CONTROL_DESTROY_FUNCTION) +(nitf_DecompressionControl ** object); + +/*! + \brief nitf_CompressionInterface - Interface object for compression + + The nitf_CompressionInterface object provides function entry points for + compressing image data. Each object handles a particular type of + compression. + +*/ + +/*! + \brief nitf_CompressionInterface - Interface object for compression + + The nitf_CompressionInterface object provides function entry points for + compressing image data. Each object handles a particular type of compression. + +*/ + +typedef struct _nitf_CompressionInterface +{ + NITF_COMPRESSION_INTERFACE_OPEN_FUNCTION open; /*!< Open compression */ + NITF_COMPRESSION_INTERFACE_START_FUNCTION start; /*!< Start compression */ + NITF_COMPRESSION_INTERFACE_WRITE_BLOCK_FUNCTION writeBlock; /*!< Write a block */ + NITF_COMPRESSION_INTERFACE_END_FUNCTION end; /*!< End compression */ + NITF_COMPRESSION_CONTROL_DESTROY_FUNCTION destroyControl; /*!< Destructor for compression control object */ + void *internal; /*!< Pointer to compression specific internal data */ +} +nitf_CompressionInterface; + +/*! + \brief nitf_DecompressionInterface - Interface object for decompression + + The nitf_DecompressionInterface object provides function entry points for + decompressing image data. Each object handles a particular type of + compression. + +*/ + +typedef struct _nitf_DecompressionInterface +{ + NITF_DECOMPRESSION_INTERFACE_OPEN_FUNCTION open; /*!< Setup the decompression object */ + NITF_DECOMPRESSION_INTERFACE_START_FUNCTION start; /*!< Prepare for first image data access */ + NITF_DECOMPRESSION_INTERFACE_READ_BLOCK_FUNCTION readBlock; /*!< Read a block */ + NITF_DECOMPRESSION_INTERFACE_FREE_BLOCK_FUNCTION freeBlock; /*!< Free block returned by readBlock */ + NITF_DECOMPRESSION_CONTROL_DESTROY_FUNCTION destroyControl; /*!< Destructor for decompression control object */ + void *internal; /*!< Pointer to decompression specific internal data */ +} +nitf_DecompressionInterface; + +/*! + \brief NITF_DOWN_SAMPLE_FUNCTION - Function pointer for down-sample + function + + The reader supports image down-sampling on read via a function interface. + The down-sample function supplies the actual functionality. + + Down-sample functions are intended to be purely numerical functions that + operate on pre-allocated buffers but it is conceivable that some more + complex algorithms might be needed to allocate memory or might not work on + some data types. Therefore an error return is allowed. + + \ar input - Input data + \ar output - Output data + \ar parameters - Processing parameters + \ar numWindowRows - Number of rows of windows + \ar numWindowCols - Number of columns of windows + \ar subWindow - Associated sub-window spec + \ar pixelType - Pixel type code + \ar pixelSize - Pixel size + \ar rowsInLastWindow - Number of valid rows in the last window + \ar colsInLastWindow - Number of valid columns in the last window + \ar error - Error object + + The parameters argument is a user supplied structure that supplies + parameter information to the down-sample fucntion. An example might be + a kernel for a convolution down-sample method. The form of the structure + is method dependent. + + \return Returns FALSE on error. + + On error, the error object is initialized. +*/ + +typedef int (*NITF_DOWN_SAMPLE_FUNCTION) (void *input, + void *output, + void *parameters, + nitf_Uint32 numWindowRows, + nitf_Uint32 numWindowCols, + nitf_SubWindow * subWindow, + nitf_Uint32 pixelType, + nitf_Uint32 pixelSize, + nitf_Uint32 rowsInLastWindow, + nitf_Uint32 colsInLastWindow, + nitf_Error * error); +/*! + \brief Constructor for the nitf_ImageIO object + + \b nitf_ImageIO_construct is the constructor for the \em nitf_ImageIO object. + The returned object must be freed via the object's destructor, + \em nitf_ImageIO_destruct + + This function does not interpret the NITF or image segment header, hence + the large number of arguments. + + The \em offset argument is the file offset to the start of the corresponding + image data segment (not the header). For some images this is the start of + the block and pad mask information + + The \em compressionRate argument is based on the conditional COMRAT NITF + image subheader field. If the field is not present the argument should be + an empty string, not a NULL pointer. + + The compressor/decompressor functions should be set to be consistant with + the compression type specified by the compression argument. NULL pointers + should be used for uncompressed images + + \param subheader From the calling image segment + \param offset Byte offset in file to image data segment + \param length Length of image data segment + \param compressor Compression interface + \param decompressor Decompression interface + \param error Error object + \return The new object or NULL on error + + On error, the user supplied error object is set. Possible errors include: + + Memory allocation error\n + Blocking mode not supported\n + Compression type not supported\n + Invalid argument\n + + The invalid argument error occurs when the block dimensions are + inconsistant with the image dimensions + +*/ + +NITFPROT(nitf_ImageIO *) +nitf_ImageIO_construct(nitf_ImageSubheader * subheader, + nitf_Uint64 offset, + nitf_Uint64 length, + nitf_CompressionInterface * compressor, + nitf_DecompressionInterface * decompressor, + nrt_HashTable* options, + nitf_Error * error); + +/*! + \brief nitf_ImageIO_clone - Clone an object + + \b nitf_ImageIO_clone creates a copy of the caller. This is a deep copy + except that any state information in the object is reset th the initial + values. Calling this function is the same as calling the constructor with + the same arguments used to create the caller. + \param image The object to clone + \return A pointer to the new object is returned. On error, NULL is returned + and the caller supplied error object is set. + + Possible errors: + + Memory allocation error +*/ + +NITFPROT(nitf_ImageIO *) nitf_ImageIO_clone(nitf_ImageIO * image, + nitf_Error * error + ); + + +/*! + \brief Destructor for the nitf_ImageIO object + + \b nitf_ImageIO_destruct deallocates the memory associated with the object. + The argument is set to NULL on return + + \param Pointer to the nitf_ImageIO object to destroy + \return None +*/ + +NITFPROT(void) nitf_ImageIO_destruct(nitf_ImageIO ** nitf); + +/*! + \brief nitf_ImageIO_read - Read a sub-window + + \b nitf_ImageIO_read reads a sub-window. The user supplies the opened file + descriptor and data buffers. The file should allow seeks. The file is left in + the file position of the last read. + + If the \em padded argument returns TRUE the request may include pad pixels. + For blocked images, each block may contain pad pixels. It is possible to + determine that a given block contains pads but it is not always possible + to tell which ones. So a request may hit a block with pad pixels but miss + the actual pixels. Thus the padded flag is only a maybe. A FALSE value + does mean that there are not pad pixels in the request. + + The user must supply one buffer for each band requested in the sub-window. + Each buffer must have enough storage for one band of the requested + sub-window size. + + Row and column skips of more than one in the sub-window are not currently + implemented. + + \param nitf The associated nitf_ImageIO object + \param io The IO interface + \param subWindow Sub-window to read + \param padded Returns TRUE if pad pixels may have been read + \param error [out] Error object + \return Returns FALSE on error + + On error, FALSE is returned and the user supplied error object is set. + + Possible errors include: + + Write in progress + Invalid sub-set or band + System I/O or memory allocation errors +*/ + +NITFPROT(NITF_BOOL) nitf_ImageIO_read(nitf_ImageIO * nitf, + nitf_IOInterface* io, + nitf_SubWindow * subWindow, + nitf_Uint8 ** user, + int *padded, + nitf_Error * error + ); + +/*! + \brief nitf_ImageIO_pixelSize - Return the pixel size + + \b nitf_ImageIO_pixelSize returns the pixel size in bytes. + + \param nitf The associated nitf_ImageIO object + \return Returns pixel size in bytes +*/ + +NITFPROT(nitf_Uint32) nitf_ImageIO_pixelSize(nitf_ImageIO * nitf); + +/*! + \brief nitf_ImageIO_setFileOffset + + \b nitf_ImageIO_setFileOffset sets the file offset to the start of the + image data. This resets the value given as the \b offset argument of the + nitf_ImageIO contructor. This value cannot be changed if an I/O operation + is in progress. + + \param nitf + \param offset The associated nitf_ImageIO offset + \param error Error object + \return FALSE is returned on error and teh error object is set + + Possible errors include: + + I/O operation in progress +*/ + +NITFPROT(NITF_BOOL) nitf_ImageIO_setFileOffset(nitf_ImageIO * nitf, + nitf_Uint64 offset, + nitf_Error * error + ); + +/*! + \brief nitf_ImageIO_getBlockingInfo - Get blocking information + + \b nitf_ImageIO_getBlockingInfo returns blocking information in a + \b nitf_BlockingInfo. The data in this structure reflects the correct + information. Due to the implementation of some compression types the + information in the image segment header may not be correct. + + The storage for the returned value is allocated for this call via the + system memory allocation method and should be freed by the caller. + + This function may have read values from the file, hence the need for the + I/O handle. This function can only be called for an existing file. + + \param image The associated ImageIO object + \param io IO interface for read + \param error Error object + \return A pointer to a \b nitf_BlockingInfo structure. On error, the error + structure is set and NULL is returned. + + Possible errors include: + + memory allocation error + I/O error +*/ + +NITFPROT(nitf_BlockingInfo *) nitf_ImageIO_getBlockingInfo(nitf_ImageIO * image, + nitf_IOInterface* io, + nitf_Error * error + ); + +/*! + \brief nitf_ImageIO_setWriteCaching - Enable/disable cached writes + + See the documentation for nitf_ImageWriter_setWriteCaching + + \return Returns the current enable/disable state +*/ + +NITFPROT(int) nitf_ImageIO_setWriteCaching +( + nitf_ImageIO * nitf, /*!< Object to modify */ + int enable /*!< Enable cached writes if true */ +); + +/*! + \brief nitf_ImageIO_setReadCaching - Enable cached reads + + See the documentation for nitf_ImageWriter_setReadCaching + + \return None +*/ + +NITFPROT(void) nitf_ImageIO_setReadCaching +( + nitf_ImageIO * nitf /*!< Object to modify */ +); + +/*! + \brief nitf_BlockingInfo_print - Print blocking information + + \b nitf_BlockingInfo_print doe a formatted print of a nitf_BlockingInfo + structure. + + If the "file" argument is NULL stdout is used. + + \return None +*/ + +NITFPROT(void) nitf_BlockingInfo_print(nitf_BlockingInfo * info, /*!< The structure to print */ + FILE * file /*!< FILE to use for print */ + ); + +/*! + \brief nitf_ImageIO_setupDirectBlockRead - Setup direct block reading + + \b nitf_ImageIO_setupDirectBlockRead does some simple checks to prepare + for reading blocks directly from the NITF (bypassing any reorganization of data) + */ +NITFPROT(NITF_BOOL) nitf_ImageIO_setupDirectBlockRead(nitf_ImageIO *nitf, + nitf_IOInterface *io, + nitf_Uint32 numBands, + nitf_Error *error); + +/*! + \brief nitf_ImageIO_readBlockDirect - Read a block of data without manipulation + + \b nitf_ImageIO_readBlockDirect reads a block of data directly from file without + any manipulation or re-organization. Only use this if you know what you're doing! + + \param nitf Image handle + \param io IO handle + \param blockNumber The block to read + \param blockSize The block size read + \param error Error object + */ +NITFPROT(nitf_Uint8*) nitf_ImageIO_readBlockDirect(nitf_ImageIO* nitf, + nitf_IOInterface* io, + nitf_Uint32 blockNumber, + nitf_Uint64* blockSize, + nitf_Error * error); + +/*! + \brief nitf_ImageIO_writeBlockDirect - Write a block of data without manipulation + + \b nitf_ImageIO_writeBlockDirect writes a block of data directly to file without + any manipulation or re-organization. The assumption here is that the data is already + formatted exactly as it needs to be and we want to avoid the performance hits of + multiple small mem copies to get the data formatted properly. Only use this if you + know what you're doing! + */ +NITFPROT(NRT_BOOL) nitf_ImageIO_writeBlockDirect(nitf_ImageIO* object, + nitf_IOInterface* io, + const nitf_Uint8 * buffer, + nitf_Uint32 blockNumber, + nitf_Error * error); + +NITF_CXX_ENDGUARD + +#endif diff --git a/modules/c/nitf/include/nitf/ImageReader.h b/modules/c/nitf/include/nitf/ImageReader.h new file mode 100644 index 000000000..bdf740057 --- /dev/null +++ b/modules/c/nitf/include/nitf/ImageReader.h @@ -0,0 +1,89 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_IMAGE_READER_H__ +#define __NITF_IMAGE_READER_H__ + +#include "nitf/ImageIO.h" +#include "nitf/System.h" + +NITF_CXX_GUARD + +/*! + * TODO: Add documentation + */ +typedef struct _nitf_ImageReader +{ + nitf_IOInterface* input; + nitf_ImageIO *imageDeblocker; + int directBlockRead; +} +nitf_ImageReader; + +/*! + * TODO: Add documentation + */ +NITFAPI(nitf_BlockingInfo *) +nitf_ImageReader_getBlockingInfo(nitf_ImageReader * imageReader, + nitf_Error * error); + +/*! + * TODO: Add documentation + */ +NITFAPI(NITF_BOOL) nitf_ImageReader_read(nitf_ImageReader * imageReader, + nitf_SubWindow * subWindow, + nitf_Uint8 ** user, + int *padded, nitf_Error * error); + +/** + Read a block directly from file + */ +NITFAPI(nitf_Uint8*) nitf_ImageReader_readBlock(nitf_ImageReader * imageReader, + nitf_Uint32 blockNumber, + nitf_Uint64* blockSize, + nitf_Error * error); + +/*! + * TODO: Add documentation + */ +NITFAPI(void) nitf_ImageReader_destruct(nitf_ImageReader ** imageReader); + +/*! + \brief nitf_ImageReader_setReadCaching - Enable cached reads + + nitf_ImageReader_setReadCaching enables cached reads. Enabling cached reads + causes the system to read full blocks of data and then satisfy individual + read requests from these buffered blocks. A cache of block buffers is + maintained. This is usually more efficent in terms of reading but requires + more memory. + + \return None +*/ + +NITFAPI(void) nitf_ImageReader_setReadCaching +( + nitf_ImageReader * iReader /*!< Object to modify */ +); + +NITF_CXX_ENDGUARD + +#endif diff --git a/modules/c/nitf/include/nitf/ImageSegment.h b/modules/c/nitf/include/nitf/ImageSegment.h new file mode 100644 index 000000000..e69ad7dda --- /dev/null +++ b/modules/c/nitf/include/nitf/ImageSegment.h @@ -0,0 +1,80 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_IMAGE_SEGMENT_H__ +#define __NITF_IMAGE_SEGMENT_H__ + +#include "nitf/System.h" +#include "nitf/ImageSource.h" +#include "nitf/ImageSubheader.h" +#include "nitf/ImageIO.h" + + +NITF_CXX_GUARD + +/*! + * \struct nitf_ImageSegment + * \brief Basically, a pair, subheader and io routines + * + * The ImageSegment object contains the sub-objects that + * make up an image, and + */ +typedef struct _nitf_ImageSegment +{ + nitf_ImageSubheader *subheader; + nitf_Uint64 imageOffset; /* Make these nitf_Off's */ + nitf_Uint64 imageEnd; /* Make these nitf_Off's */ + /*nitf_ImageSource *imageSource;*/ +} +nitf_ImageSegment; + + +/*! + * Construct a new header. This simply produces an empty + * subheader, and later, allocates an imageIO + * + * \param error + * \return An image segment or NULL + */ +NITFAPI(nitf_ImageSegment *) +nitf_ImageSegment_construct(nitf_Error * error); + + +/*! + * Clone this object. This is a deep copy operation. + * + * \param source The source object + * \param error An error to populate upon failure + * \return A new object that is identical to the old + */ +NITFAPI(nitf_ImageSegment *) +nitf_ImageSegment_clone(nitf_ImageSegment * source, nitf_Error * error); + +/*! + * Destruct an image subheader, and NULL-set it + * \param segment An image segment + */ +NITFAPI(void) nitf_ImageSegment_destruct(nitf_ImageSegment ** segment); + +NITF_CXX_ENDGUARD + +#endif diff --git a/modules/c/nitf/include/nitf/ImageSource.h b/modules/c/nitf/include/nitf/ImageSource.h new file mode 100644 index 000000000..ca1ac6399 --- /dev/null +++ b/modules/c/nitf/include/nitf/ImageSource.h @@ -0,0 +1,79 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_IMAGE_SOURCE_H__ +#define __NITF_IMAGE_SOURCE_H__ + +#include "nitf/System.h" +#include "nitf/BandSource.h" + +NITF_CXX_GUARD + +/*! + * \struct nitf_ImageSource + * \brief The base for harnessing a source. + * + * The image source holds a BandSource for every band. + * In the single band solution, this is particularly straightforward + * and performance oriented. However, it also satisfies our requirement + * to keep the bands separate, without require them to live in core. + * + * This object will be added to the ImageSegment using the + * addImageSource() method + */ +typedef struct _nitf_ImageSource +{ + nitf_List *bandSources; + int size; +} +nitf_ImageSource; + +/* ImageSources cannot be cloned!! */ + +/*! + * TODO: Add documentation + */ +NITFAPI(nitf_ImageSource *) nitf_ImageSource_construct(nitf_Error * error); + +/*! + * TODO: Add documentation + */ +NITFAPI(void) nitf_ImageSource_destruct(nitf_ImageSource **); + +/*! + * TODO: Add documentation + */ +NITFAPI(NITF_BOOL) +nitf_ImageSource_addBand(nitf_ImageSource * imageSource, + nitf_BandSource * bandSource, nitf_Error * error); + +/*! + * TODO: Add documentation + */ +NITFAPI(nitf_BandSource *) +nitf_ImageSource_getBand(nitf_ImageSource * imageSource, + int n, nitf_Error * error); + + +NITF_CXX_ENDGUARD + +#endif diff --git a/modules/c/nitf/include/nitf/ImageSubheader.h b/modules/c/nitf/include/nitf/ImageSubheader.h new file mode 100644 index 000000000..a16a8beaa --- /dev/null +++ b/modules/c/nitf/include/nitf/ImageSubheader.h @@ -0,0 +1,629 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_IMAGE_SUBHEADER_H__ +#define __NITF_IMAGE_SUBHEADER_H__ + +/* We get file security and some constants already */ +/* defined by including this first */ +#include "nitf/FileHeader.h" +#include "nitf/BandInfo.h" + +#define NITF_IM_SZ 2 +#define NITF_IID1_SZ 10 +#define NITF_IDATIM_SZ 14 +#define NITF_TGTID_SZ 17 +#define NITF_IID2_SZ 80 +#define NITF_ISCLAS_SZ 1 +#define NITF_ISORCE_SZ 42 +#define NITF_NROWS_SZ 8 +#define NITF_NCOLS_SZ 8 +#define NITF_PVTYPE_SZ 3 +#define NITF_IREP_SZ 8 +#define NITF_ICAT_SZ 8 +#define NITF_ABPP_SZ 2 +#define NITF_PJUST_SZ 1 +#define NITF_ICORDS_SZ 1 +#define NITF_IGEOLO_SZ 60 +#define NITF_NICOM_SZ 1 +#define NITF_ICOM_SZ 80 +#define NITF_IC_SZ 2 +#define NITF_COMRAT_SZ 4 +#define NITF_NBANDS_SZ 1 +#define NITF_XBANDS_SZ 5 + +/* After band info */ +#define NITF_ISYNC_SZ 1 +#define NITF_IMODE_SZ 1 +#define NITF_NBPR_SZ 4 +#define NITF_NBPC_SZ 4 +#define NITF_NPPBH_SZ 4 +#define NITF_NPPBV_SZ 4 +#define NITF_NBPP_SZ 2 +#define NITF_IDLVL_SZ 3 +#define NITF_IALVL_SZ 3 +#define NITF_ILOC_SZ 10 +#define NITF_IMAG_SZ 4 + +#define NITF_UDIDL_SZ 5 +#define NITF_UDOFL_SZ 3 +#define NITF_IXSHDL_SZ 5 +#define NITF_IXSOFL_SZ 3 + + +#define NITF_IM filePartType +#define NITF_IID1 imageId +#define NITF_IDATIM imageDateAndTime +#define NITF_TGTID targetId +#define NITF_IID2 imageTitle +#define NITF_ISCLAS imageSecurityClass +#define NITF_ISORCE imageSource +#define NITF_NROWS numRows +#define NITF_NCOLS numCols +#define NITF_PVTYPE pixelValueType +#define NITF_IREP imageRepresentation +#define NITF_ICAT imageCategory +#define NITF_ABPP actualBitsPerPixel +#define NITF_PJUST pixelJustification +#define NITF_ICORDS imageCoordinateSystem +#define NITF_IGEOLO cornerCoordinates +#define NITF_NICOM numImageComments + +/* This is the really dreadful stuff */ +#define NITF_ICOM imageComments +#define NITF_IC imageCompression +#define NITF_COMRAT compressionRate +#define NITF_NBANDS numImageBands +#define NITF_XBANDS numMultispectralImageBands + +/* This stuff is okay again */ +#define NITF_ISYNC imageSyncCode +#define NITF_IMODE imageMode +#define NITF_NBPR numBlocksPerRow +#define NITF_NBPC numBlocksPerCol +#define NITF_NPPBH numPixelsPerHorizBlock +#define NITF_NPPBV numPixelsPerVertBlock +#define NITF_NBPP numBitsPerPixel +#define NITF_IDLVL imageDisplayLevel +#define NITF_IALVL imageAttachmentLevel +#define NITF_ILOC imageLocation +#define NITF_IMAG imageMagnification + +#define NITF_UDIDL userDefinedImageDataLength +#define NITF_UDOFL userDefinedOverflow +#define NITF_IXSHDL extendedHeaderLength +#define NITF_IXSOFL extendedHeaderOverflow + +/*!< \def NITF_MAX_BAND_COUNT - Maximum band count */ +#define NITF_MAX_BAND_COUNT 99999 +#define NITF_INVALID_BAND_COUNT ((nitf_Uint32) -1) + + +NITF_CXX_GUARD + +/*! + * \brief The ImageSubheader represents all of the fields in the image header. + */ +typedef struct _nitf_ImageSubheader +{ + nitf_Field *filePartType; + nitf_Field *imageId; + nitf_Field *imageDateAndTime; + nitf_Field *targetId; + nitf_Field *imageTitle; + nitf_Field *imageSecurityClass; + + nitf_FileSecurity *securityGroup; + /* This is already identified from the file header */ + nitf_Field *encrypted; + nitf_Field *imageSource; + + nitf_Field *numRows; + nitf_Field *numCols; + + nitf_Field *pixelValueType; + nitf_Field *imageRepresentation; + nitf_Field *imageCategory; + + nitf_Field *actualBitsPerPixel; + + nitf_Field *pixelJustification; + nitf_Field *imageCoordinateSystem; + nitf_Field *cornerCoordinates; + + nitf_Field *numImageComments; + /* There are numImageComments of these */ + nitf_List* imageComments; /* list of nitf_Fields */ + + nitf_Field *imageCompression; + nitf_Field *compressionRate; + + nitf_Field *numImageBands; + nitf_Field *numMultispectralImageBands; + + /* This contains image band info stuff, including LUT */ + nitf_BandInfo **bandInfo; + + nitf_Field *imageSyncCode; + nitf_Field *imageMode; + nitf_Field *numBlocksPerRow; + nitf_Field *numBlocksPerCol; + nitf_Field *numPixelsPerHorizBlock; + nitf_Field *numPixelsPerVertBlock; + nitf_Field *numBitsPerPixel; + + nitf_Field *imageDisplayLevel; + nitf_Field *imageAttachmentLevel; + nitf_Field *imageLocation; + nitf_Field *imageMagnification; + + + nitf_Field *userDefinedImageDataLength; + nitf_Field *userDefinedOverflow; + + nitf_Field *extendedHeaderLength; + nitf_Field *extendedHeaderOverflow; + + + /* This section (unfortunately), also has a userDefinedSection */ + nitf_Extensions *userDefinedSection; + + /* This section (also unfortunately), has an extededSection as well */ + nitf_Extensions *extendedSection; + +} +nitf_ImageSubheader; + + +/*! + * Construct a new image subheader object. This object will + * be null set for every field. The object returned will be + * a full-fledged subheader, unless there is an error, in which + * case NULL will be returned, and the error object that was + * passed in will be populated. + * + * \param error In case of error, when this function returns, this + * parameter will be populated + * + * \return The image subheader, or NULL on failure. + */ +NITFAPI(nitf_ImageSubheader *)nitf_ImageSubheader_construct(nitf_Error * error); + + + +NITFAPI(nitf_ImageSubheader *) +nitf_ImageSubheader_clone(nitf_ImageSubheader * source, + nitf_Error * error); + +/*! + * Destroy and image subheader object, and NULL-set the subheader. + * A double pointer is make the NULL-set persistant on function + * exit. + * + * \param The address of the the image subheader pointer + */ +NITFAPI(void) nitf_ImageSubheader_destruct(nitf_ImageSubheader ** subhdr); + +/*! + \brief nitf_ImageSubheader_setPixelInformation - Set the pixel type and band + related information + + nitf_ImageSubheader_setPixelInformation sets the pixel type and band related + information. + + The following fields are set: + + PVTYPE + NBPP + ABPP + PJUST + NBANDS + XBANDS + IREP + ICAT + bandInfo (array of band info objects) + + The subheader bandInfo field is set using the caller supplied array. This + reference is retained and destroyed by the subheader object' destructor. + The user should not destroy the objects in the list and they should be in + persistent storage. + + Nothing is set until everything is validated. so the returned subheader is + returned unchange on error, except if the error is associated with setting + the associated Value objects. + + \return True is returned on success. On error, the error object is set. +*/ + +NITFAPI(NITF_BOOL) nitf_ImageSubheader_setPixelInformation +( + nitf_ImageSubheader *subhdr, /*!< Subheader object to set */ + const char *pvtype, /*!< Pixel value type */ + nitf_Uint32 nbpp, /*!< Number of bits/pixel */ + nitf_Uint32 abpp, /*!< Actual number of bits/pixel */ + const char *justification, /*!< Pixel justification */ + const char *irep, /*!< Image representation */ + const char *icat, /*!< Image category */ + nitf_Uint32 bandCount, /*!< Number of bands */ + nitf_BandInfo **bands, /*!< Band information object list */ + nitf_Error *error /*!< For error returns */ +); + +/*! + \brief nitf_ImageSubheader_getBandCount - Get number of bands + + nitf_ImageSubheader_getBandCount returns the number of bands in + The image associated with the subheader. The band count can come from + one of two fields, NBANDS or XBANDS. There can be errors decoding the + value fields and inconsistent values in NBANDS, XBANDS and IREP. + + If there is a problem, NITF_INVALID_BAND_COUNT is returned and the error + object is set + + \return The number of bands or an error indicator + +*/ +NITFAPI(nitf_Uint32) nitf_ImageSubheader_getBandCount +( + nitf_ImageSubheader* subhdr, /*!< The associated subheader */ + nitf_Error *error /*!< For error returns */ +); + +/*! + \brief nitf_ImageSubheader_getBandInfo - Return the band information for + an band + + nitf_ImageSubheader_getBandInfoCount returns band information for a band + specified by band number. This function range checks the band index and + returns an error if it is out of range. An error is returned if there are + no bands set. + + The function returns a pointer to the objects bandInfo field. It is + not a copy. + + \return The band information array of NULL on error + +*/ +NITFAPI(nitf_BandInfo *) nitf_ImageSubheader_getBandInfo +( + nitf_ImageSubheader* subhdr, /*!< The associated subheader */ + nitf_Uint32 band, /*!< The band index */ + nitf_Error *error /*!< For error returns */ +); + + +/*! + \brief nitf_ImageSubheader_createBands - updates NBANDS in the ImageSubheader + and allocates and constructs the Image Subheader's bandInfo array + + nitf_ImageSubheader_createBands creates the specified number of bandInfo + objects, and updates the bandInfo array. This also updates the NBANDS/XBANDS + fields in the ImageSubheader. This function assumes that the current size of + the bandInfo array is EQUAL to the current number of toatl bands (NBANDS + + XBANDS). An error is returned if memory problems occur, or if the total bands + will exceed 99999. +*/ +NITFAPI(NITF_BOOL) nitf_ImageSubheader_createBands( + nitf_ImageSubheader * subhdr, /*!< The associated subheader */ + nitf_Uint32 numBands, /*!< The number of bands to create/add*/ + nitf_Error * error /*!< For error returns */ +); + + +/*! + \brief nitf_ImageSubheader_removeBand - removes a band from the image. + + This removes the underlying BandInfo object and decrements the band count. + + \return NITF_SUCCESS is return on success, on error the error object is set. +*/ +NITFAPI(NITF_BOOL) nitf_ImageSubheader_removeBand( + nitf_ImageSubheader * subhdr, /*!< The associated subheader */ + nitf_Uint32 index, /*!< The index of the band to remove */ + nitf_Error * error /*!< For error returns */ +); + + +/*! + \brief nitf_ImageSubheader_getDimensions - Get image dimensions + + nitf_ImageSubheader_getDimensions returns the number of rows and columns + of the image. + + The only errors are associated with fetching field objects + + \return NITF_SUCCESS is return on success, on error the error object is set. +*/ + +NITFAPI(NITF_BOOL) nitf_ImageSubheader_getDimensions +( + nitf_ImageSubheader* subhdr, /*!< Associated image subheader object */ + nitf_Uint32 *numRows, /*!< Returns the number of rows */ + nitf_Uint32 *numCols, /*!< Returns the number of columns */ + nitf_Error *error /*!< Object for error messages */ +); + +/*! + \brief nitf_ImageSubheader_getBlocking - Get image blocking information + + nitf_ImageSubheader_getDimensions returns the blocking information + including number of rows and columns, number of rows and columns per block, + number of rows and columns of blocks and image mode + + The imode argument must is a char array with at least NITF_IMODE_SZ+1 bytes + + The only errors are associated with fetching field objects + + \return NITF_SUCCESS is return on success, on error the error object is set. +*/ + +NITFAPI(NITF_BOOL) nitf_ImageSubheader_getBlocking +( + nitf_ImageSubheader* subhdr, /*!< Associated image subheader object */ + nitf_Uint32 *numRows, /*!< Returns the number of rows */ + nitf_Uint32 *numCols, /*!< Returns the number of columns */ + nitf_Uint32 *numRowsPerBlock, /*!< Returns the number of rows/block */ + nitf_Uint32 *numColsPerBlock, /*!< Returns the number of columns/block */ + nitf_Uint32 *numBlocksPerRow, /*!< Returns the number of blocks/row */ + nitf_Uint32 *numBlocksPerCol, /*!< Returns the number of blocks/column */ + char *imode, /*!< Returns the image mode string */ + nitf_Error *error /*!< Object for error messages */ +); + +/*! + \brief nitf_ImageSubheader_getCompression - Get image compression + + nitf_ImageSubheader_getCompression returns the comnpression type and + compression rate strings. + + The imageCompression argument must is a char array with at least + NITF_IC_SZ+1 bytes + + The compressionRate argument must is a char array with at least + NITF_CCOMRAT_SZ+1 bytes + + The only errors are associated with fetching field objects. + + \return NITF_SUCCESS is return on success, on error the error object is set. +*/ + +NITFAPI(NITF_BOOL) nitf_ImageSubheader_getCompression +( + nitf_ImageSubheader* subhdr, /*!< Associated image subheader object */ + char *imageCompression, /*!< Returns the compression type code */ + char *compressionRate, /*!< Returns the compression rate code */ + nitf_Error *error /*!< Object for error messages */ +); + +/*! + \brief nitf_ImageSubheader_setDimensions - Set image dimensions + + nitf_ImageSubheader_setDimensions sets the number of rows and columns + of the image. The blocking is set to the simplest possible blocking given + the dimension, no blocking if possible. Blocking mode is set to B. Whether + or not blocking masks are generated is dependent on the compression code at + the time the image is written. NITF 2500C large block dimensions are not + set by this function. The more general set blocking function must be used + to specify this blocking option. + + The only errors are associated with fetching field objects + + \return TRUE is return on success, on error the error object is set. +*/ + +NITFAPI(NITF_BOOL) nitf_ImageSubheader_setDimensions +( + nitf_ImageSubheader* subhdr, /*!< Associated image subheader object */ + nitf_Uint32 numRows, /*!< The number of rows */ + nitf_Uint32 numCols, /*!< The number of columns */ + nitf_Error *error /*!< Object for error messages */ +); + +/*! + * This function allows the user to set the corner coordinates from a + * set of decimal values. This function only supports CornersTypes of + * NITF_GEO or NITF_DECIMAL. Others will trigger an error with code + * NITF_ERR_INVALID_PARAMETER + * + * In order to set up the type, you should declare a double corners[4][2]; + * The first dimension is used for the corner itself, and the second + * dimension is for lat (0) or lon (1). + * + * The corners MUST be oriented to correspond to + * + * corners[0] = (0, 0), + * corners[1] = (0, MaxCol), + * corners[2] = (MaxRow, MaxCol) + * corners[3] = (MaxRow, 0) + * + * following in line with 2500C. + */ +NITFAPI(NITF_BOOL) +nitf_ImageSubheader_setCornersFromLatLons(nitf_ImageSubheader* subheader, + nitf_CornersType type, + double corners[4][2], + nitf_Error* error); + +/*! + * Get the type of corners. This will return NITF_CORNERS_UNKNOWN + * in the event that it is not 'U', 'N', 'S', 'D', or 'G'. + * + */ +NITFAPI(nitf_CornersType) +nitf_ImageSubheader_getCornersType(nitf_ImageSubheader* subheader); + +/*! + * This function allows the user to extract corner coordinates as a + * set of decimal values. This function only supports CornersTypes of + * NITF_GEO or NITF_DECIMAL. Others will trigger an error with code + * NITF_ERR_INVALID_PARAMETER + * + * The output corners will be oriented to correspond to + * + * corners[0] = (0, 0), + * corners[1] = (0, MaxCol), + * corners[2] = (MaxRow, MaxCol) + * corners[3] = (MaxRow, 0) + * + * following in line with 2500C. + */ +NITFAPI(NITF_BOOL) +nitf_ImageSubheader_getCornersAsLatLons(nitf_ImageSubheader* subheader, + double corners[4][2], + nitf_Error *error); + +/*! + \brief nitf_ImageSubheader_computeBlocking - Compute blocking parameters + + nitf_ImageSubheader_computeBlocking computes the blocking information. The + user specifies the number of rows and columns in the image and the number of + rows and columns per block. The number of blocks per row and column is + calculated. The NITF 2500C large block option can be selected for either + dimension by setting the corresponding block dimension to 0. If + numRowsPerBlock or numColsPerBlock is over the NITF maximum, it is reduced + to 0 per 2500C. + + The number of blocks per column is a backwards way of saying the number + of rows of blocks. So the numBlocksPerCol calculation involves row counts + and numBlocksPerRow calculation involves column counts. +*/ +NITFAPI(void) +nitf_ImageSubheader_computeBlocking +( + nitf_Uint32 numRows, /*!< The number of rows */ + nitf_Uint32 numCols, /*!< The number of columns */ + nitf_Uint32* numRowsPerBlock, /*!< The number of rows/block */ + nitf_Uint32* numColsPerBlock, /*!< The number of columns/block */ + nitf_Uint32* numBlocksPerCol, /*!< The number of blocks per column */ + nitf_Uint32* numBlocksPerRow /*!< The number of blocks per row */ +); + +/*! + \brief nitf_ImageSubheader_setBlocking - Set image dimensions and blocking + + nitf_ImageSubheader_setDimensions sets the blocking information. The user + specifies the number of rows and columns in the image, number of rows and + columns per block, and blocking mode. The number of blocks per row and + column is calculated. The NITF 2500C large block option can be selected for + either dimension by setting the corresponding block dimension to 0. + + The only errors are associated with fetching field objects + + \return TRUE is return on success, on error the error object is set. +*/ +NITFAPI(NITF_BOOL) nitf_ImageSubheader_setBlocking +( + nitf_ImageSubheader* subhdr, /*!< Associated image subheader object */ + nitf_Uint32 numRows, /*!< The number of rows */ + nitf_Uint32 numCols, /*!< The number of columns */ + nitf_Uint32 numRowsPerBlock, /*!< The number of rows/block */ + nitf_Uint32 numColsPerBlock, /*!< The number of columns/block */ + const char *imode, /*!< Image mode */ + nitf_Error *error /*!< Object for error messages */ +); + +/*! + \brief nitf_ImageSubheader_setCompression - Set image compression + + nitf_ImageSubheader_getCompression sets the compression type and + compression rate + + The imageCompression argument must is a char array with at least + NITF_IC_SZ+1 bytes. The compressionRate argument must is a char array + with at least NITF_CCOMRAT_SZ+1 bytes. If either string is too long + for the field, it is truncated. + + Writing of a masked image with blocking mode S is currently not supported. + So setting a masked type such as "NM" may result in a error when the + file is written that is not detected here. + + The only errors are associated with fetching field objects. + + \return TRUE is return on success, on error the error object is set. +*/ +NITFAPI(NITF_BOOL) nitf_ImageSubheader_setCompression +( + nitf_ImageSubheader* subhdr, /*!< Associated image subheader object */ + const char *imageCompression, /*!< The compression type code */ + const char *compressionRate, /*!< The compression rate code */ + nitf_Error *error /*!< Object for error messages */ +); + + +/*! + \brief nitf_ImageSubheader_insertImageComment - insert a comment to the + array of image comments. + + This function adds the given comment string to the list of comments + associated with this image subheader. The numImageComments field + value gets incremented by 1. If the number of comments is already equal + to 9, then -1 is returned, and the comment is not added. + + The function assumes that the numImageComments field value and the actual + size of the imageComments buffer are consistent with each other. + + If the position is out of the array bounds, or less than zero, the + comment will be appended to the end. + + If the comment is NULL, a blank comment is inserted. Otherwise, the passed + comment must be a null-terminated char*. + + \return the index where the comment was inserted, or -1 if an error occurred. +*/ +NITFAPI(int) nitf_ImageSubheader_insertImageComment +( + nitf_ImageSubheader* subhdr, /*!< Associated image subheader object */ + const char* comment, /*!< Comment to add - must be null-terminated */ + int position, /*!< position to put the comment (zero-index)*/ + nitf_Error *error /*!< Object for error messages */ +); + + + +/*! + \brief nitf_ImageSubheader_removeImageComment - add a comment to the end + of the array of image comments. + + This function removes the comment at the given position from the list of + comments associated with this image subheader. The numImageComments field + value gets decremented by 1. If the number of comments is already equal + to 0, nothing is done. + + The function assumes that the numImageComments field value and the actual + size of the imageComments buffer are consistent with each other. + + If the position is out of the array bounds, or less than zero, then + nothing is done. + + \return TRUE is return on success, on error the error object is set. +*/ +NITFAPI(NITF_BOOL) nitf_ImageSubheader_removeImageComment +( + nitf_ImageSubheader* subhdr, /*!< Associated image subheader object */ + int position, /*!< position of comment to remove (zero-index)*/ + nitf_Error *error /*!< Object for error messages */ +); + + +NITF_CXX_ENDGUARD + +#endif diff --git a/modules/c/nitf/include/nitf/ImageWriter.h b/modules/c/nitf/include/nitf/ImageWriter.h new file mode 100644 index 000000000..f6c587433 --- /dev/null +++ b/modules/c/nitf/include/nitf/ImageWriter.h @@ -0,0 +1,114 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_IMAGE_WRITER_H__ +#define __NITF_IMAGE_WRITER_H__ + +#include "nitf/System.h" +#include "nitf/ImageSource.h" +#include "nitf/ImageSubheader.h" +#include "nitf/WriteHandler.h" + +NITF_CXX_GUARD + + +typedef nitf_WriteHandler nitf_ImageWriter; + +/*! + * Constructs a new ImageWriter, using the passed-in subheader as the basis + * for the values. + */ +NITFAPI(nitf_ImageWriter*) + nitf_ImageWriter_construct(nitf_ImageSubheader *subheader, + nrt_HashTable* options, + nitf_Error * error); + + +/*! + * Attach the given nitf_ImageSource to this ImageWriter + * The ImageWriter obtains ownership of the passed imageSource, and will destruct + * it when the ImageWriter is destructed. + */ +NITFAPI(NITF_BOOL) nitf_ImageWriter_attachSource(nitf_ImageWriter * writer, + nitf_ImageSource *imageSource, + nitf_Error * error); + + +/*! + * \brief nitf_ImageWriter_setWriteCaching - Enable/disable cached writes + * + * nitf_ImageWriter_setWriteCaching enables/disables cached writes. Enabling + * cached writes causes the system to accumulate full blocks of data prior to + * writing. This is more efficent in terms of writing but requires more memory. + * + * For blocking modes, R, P, and B blocking modes, one block sized buffer is + * required for each block column (number of blocks/row). For S mode one + * block is required for each band for each block column, however for the + * same iamge dimensions, pixel size and number of bands it amount to the + * same storage since the blocks of the S mode image are smaller (each + * contains only one band of data) + * + * \return Returns the current enable/disable state + */ +NITFAPI(int) nitf_ImageWriter_setWriteCaching +( + nitf_ImageWriter * iWriter, /*!< Object to modify */ + int enable /*!< Enable cached writes if true */ +); + +/*! + * \brief nitf_ImageWriter_setDirectBlockWrite - Enable/disable direct block writing + * + * nitf_ImageWriter_setDirectBlockWrite enables/disables direct block writing. + * If this is set to 1 and the number of image bands is 1, then each block of data + * will be written directly to the NITF and bypass any manipulation or re-organization. + * If you know for certain that you're band sources will give you the data formatted + * precisely as required for whatever you're writing out, then enable this for better + * write performance. This is most useful in conjunction with the DirectBlockSource + * band source for file copies. + */ +NITFAPI(void) nitf_ImageWriter_setDirectBlockWrite +( + nitf_ImageWriter * iWriter, /*!< Object to modify */ + int enable /*!< Enable cached writes if true */ +); + +/*! + * Function allows the user access to the product's pad pixels. + * For example, if you wanted transparent pixels for fill, you would + * set this function using arguments (writer, 0, 1, error) + * + * \param writer The image writer + * \param value The pixel fill value + * \param length The length in bytes of the pixel + * \param error An error to populate if the function fails + * \return NITF_SUCCESS if function succeeded, NITF_FAILURE if function + * failed + */ +NITFAPI(NITF_BOOL) nitf_ImageWriter_setPadPixel(nitf_ImageWriter* imageWriter, + nitf_Uint8* value, + nitf_Uint32 length, + nitf_Error* error); + +NITF_CXX_ENDGUARD + +#endif diff --git a/modules/c/nitf/include/nitf/LabelSegment.h b/modules/c/nitf/include/nitf/LabelSegment.h new file mode 100644 index 000000000..6161cf519 --- /dev/null +++ b/modules/c/nitf/include/nitf/LabelSegment.h @@ -0,0 +1,78 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_LABEL_SEGMENT_H__ +#define __NITF_LABEL_SEGMENT_H__ + +#include "nitf/System.h" +#include "nitf/LabelSubheader.h" + + +NITF_CXX_GUARD + +/*! + * \struct nitf_LabelSegment + * \brief ... + * + * The LabelSegment object contains the sub-objects that + * ... + */ +typedef struct _nitf_LabelSegment +{ + nitf_LabelSubheader *subheader; + nitf_Uint64 offset; + nitf_Uint64 end; + char *label; +} +nitf_LabelSegment; + + +/*! + * Construct a new header. This simply produces an empty + * subheader + * + * \param error + * \return A label header + */ +NITFAPI(nitf_LabelSegment *) +nitf_LabelSegment_construct(nitf_Error * error); + + +/*! + * Clone this object. This is a deep copy operation. + * + * \param source The source object + * \param error An error to populate upon failure + * \return A new object that is identical to the old + */ +NITFAPI(nitf_LabelSegment *) +nitf_LabelSegment_clone(nitf_LabelSegment * source, nitf_Error * error); + +/*! + * Destruct a label subheader, and NULL-set it + * \param segment A label segment + */ +NITFAPI(void) nitf_LabelSegment_destruct(nitf_LabelSegment ** segment); + +NITF_CXX_ENDGUARD + +#endif diff --git a/modules/c/nitf/include/nitf/LabelSubheader.h b/modules/c/nitf/include/nitf/LabelSubheader.h new file mode 100644 index 000000000..99eeac131 --- /dev/null +++ b/modules/c/nitf/include/nitf/LabelSubheader.h @@ -0,0 +1,124 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_LABEL_SUBHEADER_H__ +#define __NITF_LABEL_SUBHEADER_H__ + +/* We get file security and some constants already */ +/* defined by including this first */ +#include "nitf/FileHeader.h" + +#define NITF_LA_SZ 2 +#define NITF_LID_SZ 10 +#define NITF_LSCLAS_SZ 1 +#define NITF_LFS_SZ 1 +#define NITF_LCW_SZ 2 +#define NITF_LCH_SZ 2 +#define NITF_LDLVL_SZ 3 +#define NITF_LALVL_SZ 3 +#define NITF_LLOCR_SZ 5 +#define NITF_LLOCC_SZ 5 +#define NITF_LTC_SZ 3 +#define NITF_LBC_SZ 3 +#define NITF_LA filePartType +#define NITF_LID labelID +#define NITF_LSCLAS securityClass +#define NITF_LFS fontStyle +#define NITF_LCW cellWidth +#define NITF_LCH cellHeight +#define NITF_LDLVL displayLevel +#define NITF_LALVL attachmentLevel +#define NITF_LLOCR locationRow +#define NITF_LLOCC locationColumn +#define NITF_LTC textColor +#define NITF_LBC backgroundColor +#define NITF_LXSHDL_SZ 5 +#define NITF_LXSOFL_SZ 3 +#define NITF_LXSHDL extendedHeaderLength +#define NITF_LXSOFL extendedHeaderOverflow + +NITF_CXX_GUARD + +/*! + * TODO: Add documentation + */ +typedef struct _nitf_LabelSubheader +{ + nitf_Field *filePartType; + nitf_Field *labelID; + nitf_Field *securityClass; + nitf_FileSecurity *securityGroup; + nitf_Field *encrypted; + nitf_Field *fontStyle; + nitf_Field *cellWidth; + nitf_Field *cellHeight; + nitf_Field *displayLevel; + nitf_Field *attachmentLevel; + nitf_Field *locationRow; + nitf_Field *locationColumn; + nitf_Field *textColor; /* 3 raw bytes RGB */ + nitf_Field *backgroundColor; /* 3 raw bytes RGB */ + + nitf_Field *extendedHeaderLength; + nitf_Field *extendedHeaderOverflow; + + /* This section (unfortunately), has an extendedSection */ + nitf_Extensions *extendedSection; + +} +nitf_LabelSubheader; + + +/*! + * Construct a new label subheader object. This object will + * be null set for every field. The object returned will be + * a full-fledged subheader, unless there is an error, in which + * case NULL will be returned, and the error object that was + * passed in will be populated. + * + * \param error In case of error, when this function returns, this + * parameter will be populated + * + * \return The label subheader, or NULL on failure. + */ +NITFAPI(nitf_LabelSubheader *) +nitf_LabelSubheader_construct(nitf_Error * error); + +/*! + * TODO: Add documentation + */ +NITFAPI(nitf_LabelSubheader *) +nitf_LabelSubheader_clone(nitf_LabelSubheader * source, + nitf_Error * error); + +/*! + * Destroy a label subheader object, and NULL-set the subheader. + * A double pointer is make the NULL-set persistant on function + * exit. + * + * \param The address of the the label subheader pointer + */ +NITFAPI(void) nitf_LabelSubheader_destruct(nitf_LabelSubheader ** subhdr); + +NITF_CXX_ENDGUARD + +#endif diff --git a/modules/c/nitf/include/nitf/LookupTable.h b/modules/c/nitf/include/nitf/LookupTable.h new file mode 100644 index 000000000..e50d1195b --- /dev/null +++ b/modules/c/nitf/include/nitf/LookupTable.h @@ -0,0 +1,109 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, + * see . + * + */ + +#ifndef __NITF_LOOKUP_TABLE_H__ +#define __NITF_LOOKUP_TABLE_H__ + +#include "nitf/System.h" + +NITF_CXX_GUARD + +/*! + \brief nitf_LookupTable - Object representing the image sub-header lookup + table + + The nitf_LookupTable object represents the image sub-header lookup these + tables are stored in the sub-header and are used to map the image data + in some representations. These objects appear as a field in the + nitf_BandInfo object. + +*/ +typedef struct _nitf_LookupTable +{ + nitf_Uint32 tables; /*!< Number of tables */ + nitf_Uint32 entries; /*!< Number of entries per table */ + nitf_Uint8 *table; /*!< The tables */ +} +nitf_LookupTable; + +/*! + * Constructor for a LookupTable object. The numTables and numEntries are + * both set, but the LookupTable is set to NULL to start. + * + * \param numTables the number of lookupTables + * \param numEntries the number of entries per lookup table + * \param error An error to populate on a NULL return + * \return The newly allocated bandInfo object, or NULL upon failure + * + */ +NITFAPI(nitf_LookupTable *) nitf_LookupTable_construct +( + nitf_Uint32 numTables, + nitf_Uint32 numEntries, + nitf_Error * error +); + +/*! + * Clone this object. This is a deep copy operation. The lut + * is set to NULL if the source has none, and otherwise, is a + * deep copy of the LUT (clone). + * + * \param source The source object + * \param error An error to populate upon failure + * \return A new object that is identical to the old + */ +NITFAPI(nitf_LookupTable *) nitf_LookupTable_clone +( + nitf_LookupTable * source, + nitf_Error * error +); + +/*! + * Destruct this and all sub-objects. + * + * \param lut The LookupTable to destroy. We point lut at NULL. + */ +NITFAPI(void) nitf_LookupTable_destruct(nitf_LookupTable ** lut); + + +/*! + \brief nitf_LookupTable_init - Initialize a lookup table object + + nitf_LookupTable_init initialize a lookup table object. The caller must + supply an existing object, this function does not construct one. + + The tables are stored as one contiguous array. This function makes a copy + of the tables and does not retain a reference to the user argument. + + \return FALSE is returned on error and the supplied error object is set +*/ +NITFAPI(NITF_BOOL) nitf_LookupTable_init( + nitf_LookupTable * lut, /*!< The lookup table to initialize */ + nitf_Uint32 numTables, /*!< Number of tables */ + nitf_Uint32 numEntries, /*!< Number of entries in the tablt */ + const NITF_DATA * tables, /*!< The tables */ + nitf_Error * error /*!< Error object for error returns */ +); + +NITF_CXX_ENDGUARD + +#endif diff --git a/modules/c/nitf/include/nitf/PluginIdentifier.h b/modules/c/nitf/include/nitf/PluginIdentifier.h new file mode 100644 index 000000000..820525679 --- /dev/null +++ b/modules/c/nitf/include/nitf/PluginIdentifier.h @@ -0,0 +1,127 @@ +#ifndef __NITF_PLUGIN_IDENTIFIER_H__ +#define __NITF_PLUGIN_IDENTIFIER_H__ + +#define NITF_PLUGIN_INIT_SUFFIX "_init" +#define NITF_PLUGIN_CLEANUP "cleanup" +#define NITF_PLUGIN_HOOK_SUFFIX "_handler" +#define NITF_PLUGIN_CONSTRUCT_SUFFIX "_construct" +#define NITF_PLUGIN_DESTRUCT_SUFFIX "_destruct" + +#include "nitf/System.h" +#include "nitf/TRE.h" + +/* -- Plugin keys -- */ + +/*! The TRE plugin key is dependent on the NITF library version. Thus, only + * plugins built with the same version of the library will be loaded + */ +#define NITF_PLUGIN_TRE_KEY "TRE:"NITF_LIB_VERSION +#define NITF_PLUGIN_COMPRESSION_KEY "COMPRESSION" +#define NITF_PLUGIN_DECOMPRESSION_KEY "DECOMPRESSION" + + +NITF_CXX_GUARD + +struct _nitf_Record; +typedef const char **(*NITF_PLUGIN_INIT_FUNCTION) (nitf_Error * error); +typedef void (*NITF_PLUGIN_CLEANUP_FUNCTION) (void); + +/* + * \brief NITF_PLUGIN_TRE_HANDLER_FUNCTION - Function pointer for TRE handler + * +typedef int (*NITF_PLUGIN_TRE_HANDLER_FUNCTION) +( + nitf_IOInterface* io, + nitf_TRE * tre, + struct _nitf_Record* rec, + nitf_Error * error +); +*/ + +typedef nitf_TREHandler* (*NITF_PLUGIN_TRE_HANDLER_FUNCTION)(nitf_Error * error); + + +/* + \brief NITF_PLUGIN_COMPRESSION_HANDLER_FUNCTION - Function pointer for + compression handler + + The function compresses data from the user supplied buffer into a buffer + allocated by the function. The allocated buffer is returned to the user. + The function will use the system memory allocation and error handling + facilities. + + \ar input - The input buffer + \ar inputLen - Length of the input buffer in bytes + \ar output - Returns the output buffer + \ar outputLen - Returns length of the output buffer in bytes + \ar error - For error returns + + \return Returns FALSE on error + + On error, the error object is initialized. +*/ + +typedef int (*NITF_PLUGIN_COMPRESSION_HANDLER_FUNCTION) +( + nitf_Uint8 *input, + nitf_Uint32 inputLen, + nitf_Uint8 **output, + nitf_Uint32 *outputLen, + nitf_Error *error +); + +/* + \brief NITF_PLUGIN_DECOMPRESSION_CONSTRUCT_FUNCTION - Function pointer for + decompression interface object construction. + + The function creates a decompression interface object. The return type is + void * to avoid a dependency the nitf_ImageIO object. The type is actually + nitf_DecompressionInterface * + + \ar compressionType - Compression type code + \ar error - Error object + + \return Returns the new object or NULL on error. + + On error, the error object is initialized. +*/ +typedef void * (*NITF_PLUGIN_DECOMPRESSION_CONSTRUCT_FUNCTION) +( + const char *compressionType, + nitf_Error* error +); + + +typedef void * (*NITF_PLUGIN_COMPRESSION_CONSTRUCT_FUNCTION) +( + const char *compressionType, + nitf_Error* error +); + +/* + \brief NITF_PLUGIN_DECOMPRESSION_DESTRUCT_FUNCTION - Function pointer for + decompression interface object destruction. + + The function destroys a decompression interface object. The input object type + is void ** to avoid a dependency on the nitf_ImageIO object. The type i + actually nitf_DecompressionInterface **. The object argument is set to NULL + on return + + \ar object - Object to destroy + \ar error - Error object + + \return Returns FALSE on error. + + On error, the error object is initialized. +*/ +/* +typedef int (*NITF_PLUGIN_DECOMPRESSION_DESTRUCT_FUNCTION) + ( + void **object, + nitf_Error* error + ); +*/ + +NITF_CXX_ENDGUARD + +#endif diff --git a/modules/c/nitf/include/nitf/PluginRegistry.h b/modules/c/nitf/include/nitf/PluginRegistry.h new file mode 100644 index 000000000..8b8383e6f --- /dev/null +++ b/modules/c/nitf/include/nitf/PluginRegistry.h @@ -0,0 +1,192 @@ +#ifndef __NITF_PLUGIN_REGISTRY_H__ +#define __NITF_PLUGIN_REGISTRY_H__ + +#include "nitf/System.h" +#include "nitf/TRE.h" +#include "nitf/PluginIdentifier.h" +#include "nitf/ImageIO.h" + + +# define NITF_COMPRESSION_HASH_SIZE 2 +# define NITF_DECOMPRESSION_HASH_SIZE 2 + +/* The environment variable for the plugin path */ +# define NITF_PLUGIN_PATH "NITF_PLUGIN_PATH" + +NITF_CXX_GUARD + +/*! + * \file + * \brief Sort out TRE handling plugins + * + * This file is concerned with the plugin API and ensuring + * that it works. For now, the plugins come from the environment + * variable, ${NITF_PLUGIN_PATH} + * + */ +typedef struct _protected_nitf_PluginRegistry +{ + + /* For right now, for simplicity's sake, you */ + /* may only designate ONE location for plugins */ + char path[NITF_MAX_PATH]; + + /* Stick the combo of key, DLL in the hash table */ + nitf_HashTable *treHandlers; + nitf_HashTable *compressionHandlers; + nitf_HashTable *decompressionHandlers; + + nitf_List* dsos; + +} +nitf_PluginRegistry; + + +/*! + * Since 3/14/2004, this object is a singleton. If you wish to + * create it, you must call this function. This method checks + * its local static pointer to the object (using the double-check + * method) and creates it only if no such object exists. It + * loads the plugin registry and returns the object the first time. + * Subsequent calls simply return the static object pointer. + * + * By using the double-check method, we avoid costly mutex locking, + * in the event that the object has, observably, already been created. + * In the unlikely event that we have a race condition, the mutex will + * ensure that it is not in an undefined state. + * + * This singleton object is garbage-collected. Do not attempt to + * destroy it, it will auto-destruct. During construction time, + * if the object is created, but the plugin registry load fails, the object + * will destroy itself and return NULL. This is considered a MAJOR + * error, which will be probably be unrecoverable. + * + * \return In the event that this function fails, it will return NULL, + * along with an error + * + */ +NITFPROT(nitf_PluginRegistry *) + nitf_PluginRegistry_getInstance(nitf_Error * error); + + +/*! + * Load the plugin registry. This will walk the DLL path and search + * for plugins. All DSOs are loaded, and queried for their purpose. + * Once this has occurred the object will be in memory, and will be + * deletable at nitf_PluginRegistry_unload() time. Since this is normally + * called implicitly, if you use this method, you will need to synchronize + * any code that is threaded if you plan on calling these between threads. + * + * \param reg The registry to load + * \param error The error structure to populate on failure + * \return 1 on success, 0 on failure + * + */ +NITFPROT(NITF_BOOL) + nitf_PluginRegistry_load(nitf_PluginRegistry * reg, nitf_Error * error); + + +/*! + * This function allows you to register your own TRE handlers. This function + * will override any handlers that are currently handling the identifier. + */ +NITFAPI(NITF_BOOL) +nitf_PluginRegistry_registerTREHandler(NITF_PLUGIN_INIT_FUNCTION init, + NITF_PLUGIN_TRE_HANDLER_FUNCTION handler, + nitf_Error* error); + +/*! + * Public function to load the registry with plugins in the given directory. + * This will walk the DLL path and search + * for plugins. All DSOs are loaded, and queried for their purpose. + * Once this has occurred the object will be in memory, and will be + * deletable at nitf_PluginRegistry_unload() time. + * This call is thread safe. + * + * \param dirName The directory to read from and load + * \param error The error structure to populate on failure + * \return 1 on success, 0 on failure + * + */ +NITFAPI(NITF_BOOL) + nitf_PluginRegistry_loadDir(const char* dirName, nitf_Error * error); + + +NITFAPI(NITF_BOOL) + nitf_PluginRegistry_loadPlugin(const char* fullPathName, nitf_Error* error); + +/*! + * Unload the plugin registry. This will unload the DLLs and free + * the nodes in the data structure containing them. Since this is + * normally called implicitly (by the destructor at exit), if you + * choose to make this call explicitly, you will need to call it with + * locks, if you plan on sharing calls between threads. + * + * \param reg The registry + * \param error An error to populate on failure + * \return 1 on success, 0 on failure + * + */ +NITFPROT(NITF_BOOL) +nitf_PluginRegistry_unload(nitf_PluginRegistry * reg, nitf_Error * error); + +/*! + * Retrieve the plugin point of entry (NITF_PLUGIN_HANDLER_FUNCTION), so that + * the parser or writer can call it. If no such plugin exists, the + * handler will return NULL. If such a plugin DOES exist, the handler + * will return it, unless an error occurred, in which case, it sets + * had_error to 1. + * + * \param reg This is the registry + * \param ident This is the ID of the tre (the plugin will have same name) + * \param had_error If an error occured, this will be 1, otherwise it is 0 + * \param error An error to be populated if tre_main is NULL and return val + * is -1 + * \return The plugin main, or NULL + */ +NITFPROT(nitf_TREHandler*) +nitf_PluginRegistry_retrieveTREHandler(nitf_PluginRegistry * reg, + const char *ident, + int *hadError, + nitf_Error * error); + + +/*! + * Retrieve the plugin point of entry, so that + * the image io object can recieve it. If no such compression plugin, + * handler will return NULL. If such a plugin DOES exist, the handler + * will return it, unless an error occurred, in which case, it sets + * had_error to 1. + * + * \param reg This is the registry + * \param ident This is the ID (e.g., C8) + * \param had_error If an error occured, this will be 1, otherwise it is 0 + * \param error An error to be populated if tre_main is NULL and return val + * is -1 + * \return The plugin main, or NULL + */ +NITFPROT(NITF_PLUGIN_DECOMPRESSION_CONSTRUCT_FUNCTION) +nitf_PluginRegistry_retrieveDecompConstructor(nitf_PluginRegistry * reg, + const char *ident, + int *hadError, + nitf_Error * error); + + + + +NITFPROT(NITF_PLUGIN_COMPRESSION_CONSTRUCT_FUNCTION) +nitf_PluginRegistry_retrieveCompConstructor(nitf_PluginRegistry * reg, + const char *ident, + int *hadError, + nitf_Error * error); + +/* + * Retrieves a compression interface for 'comp'. Returns NULL if this fails. + */ +NITFPROT(nitf_CompressionInterface* ) +nitf_PluginRegistry_retrieveCompInterface(const char *comp, + nitf_Error* error); + +NITF_CXX_ENDGUARD + +#endif diff --git a/modules/c/nitf/include/nitf/RESegment.h b/modules/c/nitf/include/nitf/RESegment.h new file mode 100644 index 000000000..9bf0540fe --- /dev/null +++ b/modules/c/nitf/include/nitf/RESegment.h @@ -0,0 +1,76 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_RE_SEGMENT_H__ +#define __NITF_RE_SEGMENT_H__ + +#include "nitf/System.h" +#include "nitf/RESubheader.h" + + +NITF_CXX_GUARD + +/*! + * \struct nitf_RESegment + * \brief ... + * + * The RESegment object contains the sub-objects that + * make up a RES + */ +typedef struct _nitf_RESegment +{ + nitf_RESubheader *subheader; + nitf_Uint64 offset; + nitf_Uint64 end; + char *data; +} +nitf_RESegment; + + +/*! + * Construct a new (empty) segment. + * + * \param error + * \return a RES + */ +NITFAPI(nitf_RESegment *) nitf_RESegment_construct(nitf_Error * error); + + +/*! + * Clone this object. This is a deep copy operation. + * + * \param source The source object + * \param error An error to populate upon failure + * \return A new object that is identical to the old + */ +NITFAPI(nitf_RESegment *) +nitf_RESegment_clone(nitf_RESegment * source, nitf_Error * error); + +/*! + * Destruct an re subheader, and NULL-set it + * \param segment A RE segment + */ +NITFAPI(void) nitf_RESegment_destruct(nitf_RESegment ** segment); + +NITF_CXX_ENDGUARD + +#endif diff --git a/modules/c/nitf/include/nitf/RESubheader.h b/modules/c/nitf/include/nitf/RESubheader.h new file mode 100644 index 000000000..c6fd828b1 --- /dev/null +++ b/modules/c/nitf/include/nitf/RESubheader.h @@ -0,0 +1,95 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_RE_SUBHEADER_H__ +#define __NITF_RE_SUBHEADER_H__ + +/* We get file security and some constants already */ +/* defined by including this first */ +#include "nitf/FileHeader.h" + + + +#define NITF_RE_SZ 2 +#define NITF_RESTAG_SZ 25 +#define NITF_RESVER_SZ 2 +#define NITF_RESCLAS_SZ 1 +#define NITF_RESSHL_SZ 4 + +#define NITF_RE filePartType +#define NITF_RESTAG typeID +#define NITF_RESVER version +#define NITF_RESCLAS securityClass +#define NITF_RESSHL subheaderFieldsLength + +NITF_CXX_GUARD + +/*! + * TODO: Add documentation + */ +typedef struct _nitf_RESubheader +{ + nitf_Field *filePartType; + nitf_Field *typeID; + nitf_Field *version; + nitf_Field *securityClass; + nitf_FileSecurity *securityGroup; + nitf_Field *subheaderFieldsLength; + char *subheaderFields; + nitf_Uint64 dataLength; +} +nitf_RESubheader; + + +/*! + * Construct a new re subheader object. This object will + * be null set for every field. The object returned will be + * a full-fledged subheader, unless there is an error, in which + * case NULL will be returned, and the error object that was + * passed in will be populated. + * + * \param error In case of error, when this function returns, this + * parameter will be populated + * + * \return The re subheader, or NULL on failure. + */ +NITFAPI(nitf_RESubheader *) nitf_RESubheader_construct(nitf_Error * error); + +/*! + * TODO: Add documentation + */ +NITFAPI(nitf_RESubheader *) +nitf_RESubheader_clone(nitf_RESubheader * source, nitf_Error * error); + +/*! + * Destroy a re subheader object, and NULL-set the subheader. + * A double pointer is make the NULL-set persistant on function + * exit. + * + * \param The address of the the re subheader pointer + */ +NITFAPI(void) nitf_RESubheader_destruct(nitf_RESubheader ** subhdr); + + +NITF_CXX_ENDGUARD + +#endif diff --git a/modules/c/nitf/include/nitf/Reader.h b/modules/c/nitf/include/nitf/Reader.h new file mode 100644 index 000000000..4479ce8d5 --- /dev/null +++ b/modules/c/nitf/include/nitf/Reader.h @@ -0,0 +1,182 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_READER_H__ +#define __NITF_READER_H__ + +#include "nitf/System.h" +#include "nitf/PluginRegistry.h" +#include "nitf/DefaultTRE.h" +#include "nitf/Record.h" +#include "nitf/FieldWarning.h" +#include "nitf/ImageReader.h" +#include "nitf/SegmentReader.h" + +NITF_CXX_GUARD + +/*! + * \struct nitf_Reader + * \brief This object represents the 2.1 file reader + * + * This reader class contains the + * + */ +typedef struct _nitf_Reader +{ + nitf_List *warningList; + nitf_IOInterface* input; + nitf_Record *record; + NITF_BOOL ownInput; + +} +nitf_Reader; + + +/*! + * Construct a new reader + * \param error A populated structure upon failure + * \return A reader, or NULL on failure + */ +NITFAPI(nitf_Reader *) nitf_Reader_construct(nitf_Error * error); + +/*! + * Destroy a reader, set *reader to NULL + * \param reader The reader to NULL-set + */ +NITFAPI(void) nitf_Reader_destruct(nitf_Reader ** reader); + +/*! + * This is the method for reading information from a NITF (or NSIF). It + * reads all of the support data, including TREs, which it parses + * if it knows of the appropriate location. The output is a record + * of the information in the NITF. + * + * After this operation is completed, a user will typically create + * a new ImageReader using the method in this class in order to + * read the imagery from an appropriate sub-window. + * + * \param reader The reader object + * \param io The file io + * \param error A populated error if return value is zero + * \return A dynamically allocated record pointing to the internal + * support data in the NITF file + */ +NITFAPI(nitf_Record *) nitf_Reader_read(nitf_Reader * reader, + nitf_IOHandle inputHandle, + nitf_Error * error); + +/*! + * Same as the read function, except this method allows you to change + * the underlying interface. The read method calls this one using an + * IOInterface adapter. + */ +NITFAPI(nitf_Record *) nitf_Reader_readIO(nitf_Reader* reader, + nitf_IOInterface* io, + nitf_Error* error); + + +/*! + * This creates a new ImageReader object that can be used to access the + * data in the image segment. This should be done after the read() + * function has been called and a record loaded. + * + * The ImageReader object is a specialized reader for dealing with images. It is + * provided by the library, and should almost always be used when reading + * images. + * + * \param reader The reader object + * \param imageSegmentNumber The index + * \param options + * \param error A populated error if return value is zero + * \return new nitf_ImageReader* for the image in question + */ +NITFAPI(nitf_ImageReader *) nitf_Reader_newImageReader +( + nitf_Reader *reader, + int imageSegmentNumber, + nrt_HashTable* options, + nitf_Error * error +); + + +/*! + * This creates a new SegmentReader object that can be used to access the + * data in the text segment. + * + * \param reader The reader object + * \param textSegmentNumber The index + * \param error A populated error if return value is zero + * \return new nitf_SegmentReader* for the segment in question + */ +NITFAPI(nitf_SegmentReader*) nitf_Reader_newTextReader +( + nitf_Reader *reader, + int textSegmentNumber, + nitf_Error * error +); + + +/*! + * This creates a new SegmentReader object that can be used to access the + * data in the graphic segment. + * + * \param reader The reader object + * \param graphicSegmentNumber The index + * \param error A populated error if return value is zero + * \return new nitf_SegmentReader* for the segment in question + */ +NITFAPI(nitf_SegmentReader*) nitf_Reader_newGraphicReader +( + nitf_Reader *reader, + int graphicSegmentNumber, + nitf_Error * error +); + +/*! + * This creates a new DEReader object that can be used to access the + * data in the DE segment. + * + * \param reader The reader object + * \param DESegmentNumber The index + * \param error A populated error if return value is zero + * \return new nitf_DEReader* for the segment in question + */ +NITFAPI(nitf_SegmentReader *) nitf_Reader_newDEReader +( + nitf_Reader *reader, + int DESegmentNumber, + nitf_Error * error +); + + +/*! + * Return the NITFVersion of the file passed in by its file name. + * This is a static method (not associated with a specific Reader). + * \param fileName The name of the file to check + * \return NITFVersion of the file + */ +NITFAPI(nitf_Version) nitf_Reader_getNITFVersion(const char* fileName); + + +NITF_CXX_ENDGUARD + +#endif diff --git a/modules/c/nitf/include/nitf/Record.h b/modules/c/nitf/include/nitf/Record.h new file mode 100644 index 000000000..94e132eb3 --- /dev/null +++ b/modules/c/nitf/include/nitf/Record.h @@ -0,0 +1,511 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_RECORD_H__ +#define __NITF_RECORD_H__ + +#include "nitf/System.h" +#include "nitf/FileHeader.h" +#include "nitf/ImageSegment.h" +#include "nitf/GraphicSegment.h" +#include "nitf/LabelSegment.h" +#include "nitf/TextSegment.h" +#include "nitf/DESegment.h" +#include "nitf/RESegment.h" + +NITF_CXX_GUARD + +/*! + * \struct nitf_Record + * \brief This is a record of the file + * + * The Record object is a representation of the data within + * a file. It is structurally hierarchical in a manner that + * corresponds one-to-one with the components of an NITF file. + * For most occurences, you can assume that reader will + * est the header + */ +typedef struct _nitf_Record +{ + /* The file header */ + nitf_FileHeader *header; + + /* List of ImageSegments */ + nitf_List *images; + + /* List of GraphicsSegments */ + nitf_List *graphics; + + /* List of LabelSegments (2.0 only) */ + nitf_List *labels; + + /* List of TextSegments */ + nitf_List *texts; + + /* List of data extensions segments (DES) */ + nitf_List *dataExtensions; + + /* List of reserved segments (RES) */ + nitf_List *reservedExtensions; +} +nitf_Record; + +#define NITF_INVALID_NUM_SEGMENTS(I) ((I < 0) || (I > 999)) + +/*! + * Create a new record. This allocates the Record itself, its FileHeader, + * and inits all of the Lists of segments to be empty. + * It NULL-sets everything else. + * The FVER (fileVersion) field of the FileHeader is also set, based + * on the version specified. If an invalid version is specified, + * NITF_VER_21 is assumed, creating a NITF 2.1 record. + * + * If an error should occur, the function will return NULL, + * and the error object will be populated + * \param version The nitf_Version of the Record + * \param error An error to populate if a problem occurs + * \return A record to return + * + */ +NITFAPI(nitf_Record *) nitf_Record_construct(nitf_Version version, + nitf_Error * error); + + +/*! + * Clone this object. This is a deep copy operation. + * + * \param source The source object + * \param error An error to populate upon failure + * \return A new object that is identical to the old + */ +NITFAPI(nitf_Record *) nitf_Record_clone(nitf_Record * source, + nitf_Error * error); + +/*! + * Destroy a record and NULL-set it + * \param record A record to destroy + */ +NITFAPI(void) nitf_Record_destruct(nitf_Record ** record); + + +/*! + * Returns the nitf_Version enum for the Record in the Reader + * + * \note In version 2.5 of NITRO, the error is eliminated, since + * it is not possible to test, and is not being set + * + * \param record the Record object + * \return nitf_Version enum specifying the version + */ +NITFAPI(nitf_Version) nitf_Record_getVersion(nitf_Record * record); + + +/*! + * Utility function gets the number of images out of the record. + * Just goes into the FHDR and gets out NUMI and converts the + * field to a Uint32 + * + * \param record The record + * \param error An error to populate on failure + * \return We will return a value that can be tested using + * NITF_INVALID_NUM_SEGMENTS(rv) + */ +NITFAPI(nitf_Uint32) nitf_Record_getNumImages(nitf_Record* record, + nitf_Error* error); + +/*! + * Creates and returns a new ImageSegment* that is bound to the Record + * + * Note: The accompanying ComponentInfo object for this segment is also + * created and added to the FileHeader structure for it + * + * \param record the Record object + * \param error The error to populate on failure + * \return nitf_ImageSegment* that is bound to the Record + */ +NITFAPI(nitf_ImageSegment*) nitf_Record_newImageSegment(nitf_Record * record, + nitf_Error * error); + +/*! + * Utility function gets the number of graphics out of the record. + * Just goes into the FHDR and gets out NUMS and converts the + * field to a Uint32 + * + * \param record The record + * \param error An error to populate on failure + * \return We will return a value that can be tested using + * NITF_INVALID_NUM_SEGMENTS(rv) + */ +NITFAPI(nitf_Uint32) nitf_Record_getNumGraphics(nitf_Record* record, + nitf_Error* error); + +/*! + * Creates and returns a new GraphicSegment* that is bound to the Record + * + * Note: The accompanying ComponentInfo object for this segment is also + * created and added to the FileHeader structure for it + * + * \param record the Record object + * \param error The error to populate on failure + * \return nitf_GraphicSegment* that is bound to the Record + */ +NITFAPI(nitf_GraphicSegment*) +nitf_Record_newGraphicSegment(nitf_Record * record, + nitf_Error * error); + + +/*! + * Utility function gets the number of texts out of the record. + * Just goes into the FHDR and gets out NUMT and converts the + * field to a Uint32 + * + * \param record The record + * \param error An error to populate on failure + * \return We will return a value that can be tested using + * NITF_INVALID_NUM_SEGMENTS(rv) + */ +NITFAPI(nitf_Uint32) nitf_Record_getNumTexts(nitf_Record* record, + nitf_Error* error); + +/*! + * Creates and returns a new TextSegment* that is bound to the Record + * + * Note: The accompanying ComponentInfo object for this segment is also + * created and added to the FileHeader structure for it + * + * \param record the Record object + * \param error The error to populate on failure + * \return nitf_TextSegment* that is bound to the Record + */ +NITFAPI(nitf_TextSegment*) nitf_Record_newTextSegment(nitf_Record * record, + nitf_Error * error); + + + +/*! + * Utility function gets the number of DES out of the record. + * Just goes into the FHDR and gets out NUMDES and converts the + * field to a Uint32 + * + * \param record The record + * \param error An error to populate on failure + * \return We will return a value that can be tested using + * NITF_INVALID_NUM_SEGMENTS(rv) + */ +NITFAPI(nitf_Uint32) nitf_Record_getNumDataExtensions(nitf_Record* record, + nitf_Error* error); + +/*! + * Creates and returns a new DESegment* that is bound to the Record + * + * Note: The accompanying ComponentInfo object for this segment is also + * created and added to the FileHeader structure for it + * + * \param record the Record object + * \param error The error to populate on failure + * \return nitf_DESegment* that is bound to the Record + */ +NITFAPI(nitf_DESegment*) +nitf_Record_newDataExtensionSegment(nitf_Record * record, + nitf_Error * error); + + +/*! + * This removes the segment at the given offset. The segment is + * de-allocated, and removed from the system. + * + * CAUTION!!! -- Removing a segment removes the memory in the segment list, + * so any usage of the segment will cause a segmentation fault. + * + * \param segmentNumber + * \throws NITFException + */ +NITFAPI(NITF_BOOL) nitf_Record_removeImageSegment +( + nitf_Record * record, + nitf_Uint32 segmentNumber, + nitf_Error * error +); + +/*! + * This removes the segment at the given offset. The segment is + * de-allocated, and removed from the system. + * + * CAUTION!!! -- Removing a segment removes the memory in the segment list, + * so any usage of the segment will cause a segmentation fault. + * + * \param segmentNumber + * \throws NITFException + */ +NITFAPI(NITF_BOOL) nitf_Record_removeGraphicSegment +( + nitf_Record * record, + nitf_Uint32 segmentNumber, + nitf_Error * error +); + + +/*! + * Utility function gets the number of labels out of the record. + * Just goes into the FHDR and gets out NUMX and converts the + * field to a Uint32 + * + * \param record The record + * \param error An error to populate on failure + * \return We will return a value that can be tested using + * NITF_INVALID_NUM_SEGMENTS(rv) + */ +NITFAPI(nitf_Uint32) nitf_Record_getNumLabels(nitf_Record* record, + nitf_Error* error); + + +/*! + * This removes the segment at the given offset. The segment is + * de-allocated, and removed from the system. + * + * CAUTION!!! -- Removing a segment removes the memory in the segment list, + * so any usage of the segment will cause a segmentation fault. + * + * \param segmentNumber + * \throws NITFException + */ +NITFAPI(NITF_BOOL) nitf_Record_removeLabelSegment +( + nitf_Record * record, + nitf_Uint32 segmentNumber, + nitf_Error * error +); + +/*! + * This removes the segment at the given offset. The segment is + * de-allocated, and removed from the system. + * + * CAUTION!!! -- Removing a segment removes the memory in the segment list, + * so any usage of the segment will cause a segmentation fault. + * + * \param segmentNumber + * \throws NITFException + */ +NITFAPI(NITF_BOOL) nitf_Record_removeTextSegment +( + nitf_Record * record, + nitf_Uint32 segmentNumber, + nitf_Error * error +); + +/*! + * This removes the segment at the given offset. The segment is + * de-allocated, and removed from the system. + * + * CAUTION!!! -- Removing a segment removes the memory in the segment list, + * so any usage of the segment will cause a segmentation fault. + * + * \param segmentNumber + * \throws NITFException + */ +NITFAPI(NITF_BOOL) nitf_Record_removeDataExtensionSegment +( + nitf_Record * record, + nitf_Uint32 segmentNumber, + nitf_Error * error +); + + +/*! + * Utility function gets the number of RES out of the record. + * Just goes into the FHDR and gets out NUMRES and converts the + * field to a Uint32 + * + * \param record The record + * \param error An error to populate on failure + * \return We will return a value that can be tested using + * NITF_INVALID_NUM_SEGMENTS(rv) + */ +NITFAPI(nitf_Uint32) nitf_Record_getNumReservedExtensions(nitf_Record* record, + nitf_Error* error); + +/*! + * This removes the segment at the given offset. The segment is + * de-allocated, and removed from the system. + * + * CAUTION!!! -- Removing a segment removes the memory in the segment list, + * so any usage of the segment will cause a segmentation fault. + * + * \param segmentNumber + * \throws NITFException + */ +NITFAPI(NITF_BOOL) nitf_Record_removeReservedExtensionSegment +( + nitf_Record * record, + nitf_Uint32 segmentNumber, + nitf_Error * error +); + +/*! + * This moves the segment from the oldIndex to the newIndex. + * This is a shortcut for: + * nitf_List_move(record->images, oldIndex, newIndex, error); + * + * \param oldIndex the index of the segment to move + * \param newIndex the index where the segment will be moved to + * \throws NITFException + */ +NITFAPI(NITF_BOOL) nitf_Record_moveImageSegment +( + nitf_Record * record, + nitf_Uint32 oldIndex, + nitf_Uint32 newIndex, + nitf_Error * error +); + +/*! + * This moves the segment from the oldIndex to the newIndex. + * This is a shortcut for: + * nitf_List_move(record->graphics, oldIndex, newIndex, error); + * + * \param oldIndex the index of the segment to move + * \param newIndex the index where the segment will be moved to + * \throws NITFException + */ +NITFAPI(NITF_BOOL) nitf_Record_moveGraphicSegment +( + nitf_Record * record, + nitf_Uint32 oldIndex, + nitf_Uint32 newIndex, + nitf_Error * error +); + +/*! + * This moves the segment from the oldIndex to the newIndex. + * This is a shortcut for: + * nitf_List_move(record->labels, oldIndex, newIndex, error); + * + * \param oldIndex the index of the segment to move + * \param newIndex the index where the segment will be moved to + * \throws NITFException + */ +NITFAPI(NITF_BOOL) nitf_Record_moveLabelSegment +( + nitf_Record * record, + nitf_Uint32 oldIndex, + nitf_Uint32 newIndex, + nitf_Error * error +); + +/*! + * This moves the segment from the oldIndex to the newIndex. + * This is a shortcut for: + * nitf_List_move(record->texts, oldIndex, newIndex, error); + * + * \param oldIndex the index of the segment to move + * \param newIndex the index where the segment will be moved to + * \throws NITFException + */ +NITFAPI(NITF_BOOL) nitf_Record_moveTextSegment +( + nitf_Record * record, + nitf_Uint32 oldIndex, + nitf_Uint32 newIndex, + nitf_Error * error +); + +/*! + * This moves the segment from the oldIndex to the newIndex. + * This is a shortcut for: + * nitf_List_move(record->dataExtensions, oldIndex, newIndex, error); + * + * \param oldIndex the index of the segment to move + * \param newIndex the index where the segment will be moved to + * \throws NITFException + */ +NITFAPI(NITF_BOOL) nitf_Record_moveDataExtensionSegment +( + nitf_Record * record, + nitf_Uint32 oldIndex, + nitf_Uint32 newIndex, + nitf_Error * error +); + +/*! + * This moves the segment from the oldIndex to the newIndex. + * This is a shortcut for: + * nitf_List_move(record->reservedExtensions, oldIndex, newIndex, error); + * + * \param oldIndex the index of the segment to move + * \param newIndex the index where the segment will be moved to + * \throws NITFException + */ +NITFAPI(NITF_BOOL) nitf_Record_moveReservedExtensionSegment +( + nitf_Record * record, + nitf_Uint32 oldIndex, + nitf_Uint32 newIndex, + nitf_Error * error +); + +/*! + * nitf_Record_mergeTREs merges TREs between all segments and the associate + * TRE_OVERFLOW segments. After this call all TRE_OVERFLOW (DE) segments are + * removed and their TRE's have been added to the TRE list of the corresponding + * extension in the corresponding section. + * + * \param The record or operate on + * \param error An error to populate if a problem occurs + * \return TRUE on success, false on failure + * +*/ +NITFAPI(NITF_BOOL) nitf_Record_mergeTREs +( + nitf_Record * record, + nitf_Error * error +); + +/*! + * nitf_Record_unmergeTREs scans all segments and creates TRE_OVERFLOW (DE) + * segments for each segment that requires one. When an overflow segment is + * created,TREs are transfered from the original segment to the overflow. + * The TRE order in the combined lists, original and overflows replicates the + * order of the orginal TRE list. As many TREs as will fit are placed in the + * original segment, but the orginal list is not reordered. + * + * This function will be automatically be called by the writer, but may be + * called by the user. Once a segment has been unmerged to create an overflow + * segment, subsequent unmerges will do nothing and additional TREs are added + * to the overflow segment. Also after unmerging, the user must be cognicant + * of the presence of the overflow segment when preocessing TREs for the + * original segment. An unmerged segment can be remerged. + * + * \param The record or operate on + * \param error An error to populate if a problem occurs + * \return TRUE on success, false on failure + * +*/ +NITFAPI(NITF_BOOL) nitf_Record_unmergeTREs +( + nitf_Record * record, + nitf_Error * error +); + + +NITF_CXX_ENDGUARD + +#endif diff --git a/modules/c/nitf/include/nitf/RowSource.h b/modules/c/nitf/include/nitf/RowSource.h new file mode 100644 index 000000000..d6c32de16 --- /dev/null +++ b/modules/c/nitf/include/nitf/RowSource.h @@ -0,0 +1,94 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +/* + \file RowSource - Band source implementation for data produced in rows + + The RowSource object is derived from the DataSource object and is used for + algorithms that generate data in rows. The RowSource object provides a + wrapper to integrate a row oriented algorithm into the Writer source model. + + An example is the generation of the magnitude of a complex function. If the + intended input image is very large and memory constraints prevent reading + the entire image into memory, this simple algorithm could be implemented by + reading the input in groups of full rows (strips), transforming each strip + and then writing the rows to the output file. + + The algorithm must be organized into an object that allows generation of + individual rows. In the example, the algorthm object would have to have a + a setup function that initializes whatever state is required to begin + processing rows. A "nextRow" method is required as well as a clean-up + function. The "nextRow" function specifies the band and the algorithm + object and must be able to provide the row data one band at a time. The + caller is responsible for the making the set-up and clean-up calls and the + object must handle input processing. The object may make the following two + assumptions (only): + + Requests to the object are sequential, no seeks + Requests to the object are in units of whole rows + Bands from the same image source are read in parallel + +*/ + +#ifndef __NITF_ROW_SOURCE_H__ +#define __NITF_ROW_SOURCE_H__ + +#include "nitf/BandSource.h" + +NITF_CXX_GUARD + +/*! + \brief NITF_ROW_SOURCE_NEXT_ROW - Next row function prototype + + \param algorithm - The algorithm object + \param band - The requested band + \param buffer - The buffer to receive the data + \param error - Error object for error returns + + \return Returns true on success. On failure the error object is set +*/ +typedef NITF_BOOL(*NITF_ROW_SOURCE_NEXT_ROW) (void *algorithm, + nitf_Uint32 band, + NITF_DATA * buffer, + nitf_Error * error); + +/* + \brief nitf_RowSource_construct - Constructor for the RowSource object + + The constructor for the row source object. This object maintains state + information and cannot be reused for a second write. + + \return The new object or NULL on error. On error, the error object is + set +*/ +NITFAPI(nitf_BandSource *) nitf_RowSource_construct +( + void *algorithm, /*!< The algorithm object */ + NITF_ROW_SOURCE_NEXT_ROW nextRow, /*!< Pointer to the next row function */ + nitf_Uint32 band, /*!< Associate output band */ + nitf_Uint32 numRows, /*!< Number of rows */ + nitf_Uint32 rowLength, /*!< Length of each row in bytes (single band) */ + nitf_Error * error /*!< For error returns */ +); + +NITF_CXX_ENDGUARD +#endif diff --git a/modules/c/nitf/include/nitf/SegmentReader.h b/modules/c/nitf/include/nitf/SegmentReader.h new file mode 100644 index 000000000..ee1ac801d --- /dev/null +++ b/modules/c/nitf/include/nitf/SegmentReader.h @@ -0,0 +1,166 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_SEGMENT_READER_H__ +#define __NITF_SEGMENT_READER_H__ + +#include "nitf/System.h" + +NITF_CXX_GUARD + + +/*! + \brief nitf_SegmentReader - Reader object for reading Segments + + The nitf_SegmentReader object provides support for reading segment data. A simple + byte stream oriented model is provided that presents the data as a self- + contained, flat file of bytes. Seeking within the virtual file is permitted. + + The segment reader uses the IOHandle supplied (and retained) by the Reader + during the nitf_Reader_read call which must precede the use of the + segment reader. The user must not use this IOHandle during the read of the + data. The file position of this handle is maintained by the segment reader + and it may not move in a way that is consistent with the movement of + the pointer in the virtual file. + + The constructor for this object is a method of the nitf_Reader object. The + methods available are: + nitf_Reader_newTextReader + nitf_Reader_newGraphicReader + + + \param input The input interface + \param dataLength The length of the user data + \param baseOffset Offset to the start of data + \param virtualOffset current offset (within this region) +*/ + +typedef struct _nitf_SegmentReader +{ + nitf_IOInterface* input; + nitf_Uint32 dataLength; + nitf_Uint64 baseOffset; + nitf_Uint64 virtualOffset; +} +nitf_SegmentReader; + + + + +/*! + \brief nitf_SegmentReader_read - Read segment data + + The nitf_SegmentReader_read function reads data from the associated segment. + The reading of the data is serial as if a flat file were being read by an + input stream. Except for the first argument, this function has the same + calling sequence and behavior as IOHandle_read. + + \return TRUE is returned on success. On error, the error object + is set. +*/ + +NITFAPI(NITF_BOOL) nitf_SegmentReader_read +( + nitf_SegmentReader *segmentReader, /*!< Associated SegmentReader */ + NITF_DATA *buffer, /*!< Buffer to hold data */ + size_t count, /*!< Amount of data to return */ + nitf_Error *error /*!< For error returns */ +); + +/*! + \brief nitf_SegmentReader_seek - Seek in segment data + + The nitf_SegmentReader_seek function allows the user to seek within the extension + data. Except for the first argument, this function has the same calling + sequence and behaivior as IOHandle_seek. The offset is relative to the top + of the segment data. + + The returned value maybe tested with NITF_IO_SUCCESS() + + \return The offset from the beginning to the current position + is set. +*/ + +NITFAPI(nitf_Off) nitf_SegmentReader_seek +( + nitf_SegmentReader *segmentReader, /*!< Associated SegmentReader */ + nitf_Off offset, /*!< The seek offset */ + int whence, /*!< Starting at (SEEK_SET, SEEK_CUR, SEEK_END)*/ + nitf_Error *error /*!< For error returns */ +); + +/*! + \brief nitf_SegmentReader_tell - Tell location in segment data + + The nitf_SegmentReader_tell function allows the user to determine the current + offset within the extension data. Except for the first argument, this + function has the same calling sequence and behaivior as IOHandle_tell. The + offset is relative to the top of the segment data. + + The returned value maybe tested with NITF_IO_SUCCESS() + + \return The offset from the beginning to the current position + is set. +*/ + +NITFAPI(nitf_Off) nitf_SegmentReader_tell +( + nitf_SegmentReader *segmentReader, /*!< Associated SegmentReader */ + nitf_Error *error /*!< For error returns */ +); + +/*! + \brief nitf_SegmentReader_getSize - Determine size of the data + + The nitf_SegmentReader_seek function allows the user to determine the size of + the data. Except for the first argument, this function has the same calling + sequence and behavior as IOHandle_getSize. + + The returned value maybe tested with NITF_IO_SUCCESS() + + \return The offset from the beginning to the current position + is set. +*/ + +NITFAPI(nitf_Off) nitf_SegmentReader_getSize +( + nitf_SegmentReader *segmentReader, /*!< Associated SegmentReader */ + nitf_Error *error /*!< For error returns */ +); + +/*! + \brief nitf_SegmentReader_destruct - Destructor for the SegmentReader object + + nitf_SegmentReader_destruct is the destructor for the SegmentReader object. + This function does not close the associated file handle. + + \return None +*/ + +NITFAPI(void) nitf_SegmentReader_destruct +( + nitf_SegmentReader **segmentReader /*!< Associated SegmentReader */ +); + +NITF_CXX_ENDGUARD + +#endif diff --git a/modules/c/nitf/include/nitf/SegmentSource.h b/modules/c/nitf/include/nitf/SegmentSource.h new file mode 100644 index 000000000..216db0d3b --- /dev/null +++ b/modules/c/nitf/include/nitf/SegmentSource.h @@ -0,0 +1,119 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_SEGMENT_SOURCE_H__ +#define __NITF_SEGMENT_SOURCE_H__ + +#include "nitf/System.h" +#include "nitf/DataSource.h" +#include "nitf/SegmentReader.h" + + +NITF_CXX_GUARD + + +/*! + * Typedef nitf_BandSource + */ +typedef nitf_DataSource nitf_SegmentSource; + + +/*! + * Define nitf_SegmentSource_destruct which is just nitf_DataSource_destruct + */ +#define nitf_SegmentSource_destruct nitf_DataSource_destruct + + +/*! + * \fn nitf_SegmentMemorySource_construct + * \brief A class for reading segment data from memory (or VM) + * + * The memory source class allows us to read directly from + * a data buffer. In the event that this is a memory-mapped file, + * we will likely get a performance gain over the direct fd approach. + * + * The constructor takes in a buffer, a size, and optionally + * a sampling factor (Typically, the factor will be applied most + * times during the case of memory mapping, although it may + * be used to sample down or cut the image into pieces). + * + * Contains a static declaration of the specific implementation. + * + * \param data The data + * \param size The size + * \param start The start offset + * \param byteSkip The number of bytes to skip (0 signifies contiguous read) + * \param copyData Whether or not to make a copy of the data. If this is + * false, the data must outlive the memory source. + */ +NITFAPI(nitf_SegmentSource *) nitf_SegmentMemorySource_construct +( + const char* data, + nitf_Off size, + nitf_Off start, + int byteSkip, + NITF_BOOL copyData, + nitf_Error* error +); + +/*! + * \fn nitf_SegmentFileSource_construct + * \brief Provides impl for reading segment data from an FD or HANDLE + * + * The FileSource class is a DataSource that comes from an open + * file descriptor or handle. Due to any number of constraints, + * we allow the creator to specify a start point, and a byte skip. + * + * Construct a file source from a handle, a start point, and + * a pixel skip. + * + * \param fname The file to use + * \param start The location to seek to (as the beginning) + * \param byteSkip The number of bytes to skip(0 signifies contiguous read) + */ +NITFAPI(nitf_SegmentSource *) nitf_SegmentFileSource_construct +( + nitf_IOHandle handle, + nitf_Off start, + int byteSkip, + nitf_Error * error +); + + +NITFAPI(nitf_SegmentSource *) nitf_SegmentFileSource_constructIO +( + nitf_IOInterface* io, + nitf_Off start, + int byteSkip, + nitf_Error * error +); + +NITFAPI(nitf_SegmentSource *) nitf_SegmentReaderSource_construct +( + nitf_SegmentReader *reader, + nitf_Error * error +); + + +NITF_CXX_ENDGUARD + +#endif diff --git a/modules/c/nitf/include/nitf/SegmentWriter.h b/modules/c/nitf/include/nitf/SegmentWriter.h new file mode 100644 index 000000000..edd8555b3 --- /dev/null +++ b/modules/c/nitf/include/nitf/SegmentWriter.h @@ -0,0 +1,51 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_SEGMENT_WRITER_H__ +#define __NITF_SEGMENT_WRITER_H__ + +#include "nitf/System.h" +#include "nitf/SegmentSource.h" +#include "nitf/WriteHandler.h" + +NITF_CXX_GUARD + +typedef nitf_WriteHandler nitf_SegmentWriter; + +/*! + * Constructs a new SegmentWriter. + */ +NITFAPI(nitf_SegmentWriter*) nitf_SegmentWriter_construct(nitf_Error *error); + +/*! + * Attach the given segmentSource to this Writer + * The Writer obtains ownership of the passed segmentSource, and will destruct + * it when the Writer is destructed. + */ +NITFAPI(NITF_BOOL) nitf_SegmentWriter_attachSource(nitf_SegmentWriter *writer, + nitf_SegmentSource *segmentSource, + nitf_Error *error); + + +NITF_CXX_ENDGUARD + +#endif diff --git a/modules/c/nitf/include/nitf/StreamIOWriteHandler.h b/modules/c/nitf/include/nitf/StreamIOWriteHandler.h new file mode 100644 index 000000000..130a6ffdf --- /dev/null +++ b/modules/c/nitf/include/nitf/StreamIOWriteHandler.h @@ -0,0 +1,52 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_STREAM_IO_WRITE_HANDLER_H__ +#define __NITF_STREAM_IO_WRITE_HANDLER_H__ + +#include "nitf/System.h" +#include "nitf/WriteHandler.h" + + +NITF_CXX_GUARD + +/** + * Create a WriteHandler that streams from an input IO source. This is useful + * if you want to bypass any specialized WriteHandlers and/or your data is + * already in the desired format. + * + * \param inputHandle The input IOHandle + * \param offset The offset of the IOHandle to start from + * \param bytes The # of bytes to write + * \param error The error object, which will get populated on error + * \return a nitf_WriteHandler*, or NULL on error + */ +NITFAPI(nitf_WriteHandler*) nitf_StreamIOWriteHandler_construct( + nitf_IOInterface *io, + nitf_Uint64 offset, + nitf_Uint64 bytes, + nitf_Error *error); + + +NITF_CXX_ENDGUARD + +#endif diff --git a/modules/c/nitf/include/nitf/SubWindow.h b/modules/c/nitf/include/nitf/SubWindow.h new file mode 100644 index 000000000..b1a0fadbe --- /dev/null +++ b/modules/c/nitf/include/nitf/SubWindow.h @@ -0,0 +1,108 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_SUB_WINDOW_H__ +#define __NITF_SUB_WINDOW_H__ + +#include "nitf/System.h" +#include "nitf/DownSampler.h" + + +NITF_CXX_GUARD + +/*! + * \struct nitf_SubWindow + * \brief Sub-window specification structure + * + * The \b nitf_SubWindow specifies a sub-window. This object is used as an + * argument to image read and write requests to specify the data requested. + * + * The \em bandList field specifies the desired bands. Bands are numbered + * starting with zero and ordered as the bands appear physically in the file. + * The user must supply one buffer for each requested band. Each buffer must + * have enough storage for one band of the requested subimage size. + * + * The downsampler determines what downsampling (if any) is performed on + * this sub-window request. There is no default downsampler. If you just + * want to perform pixel skipping, call setDownSampler() with a + * PixelSkip object. + */ +typedef struct _nitf_SubWindow +{ + nitf_Uint32 startRow; /*!< Start row */ + nitf_Uint32 startCol; /*!< Start column */ + + nitf_Uint32 numRows; /*!< Number of rows to read */ + nitf_Uint32 numCols; /*!< Number of columns to read */ + + nitf_Uint32 *bandList; /*!< List of bands to read */ + nitf_Uint32 numBands; /*!< Number of bands to read */ + + nitf_DownSampler *downsampler; /* A downsampler, if any */ + +} +nitf_SubWindow; + + +/*! + * \fn nitf_SubWindow_construct(error) + * + * This method constructs a new sub-window. The sub-window defaults + * to all zeroes (meaning that the user must assign values to each + * field). The downsampler is a method for sub-sampling, if necessary. + * This defaults to a NULL (or NO downsampler necessary). + * + * \param error The error to populate on failure + * \return Returns a sub-window object on success, and NULL on failure + */ +NITFAPI(nitf_SubWindow *) nitf_SubWindow_construct(nitf_Error * error); + +/*! + * \fn nitf_SubWindow_destruct(subWindow) + * + * Destroys a sub-window. This method will NOT destroy your + * downsampler, since you may want to reuse it for multiple objects. + * It also does not destroy the band list since how the list was created + * (i.e., NITF_MALLOC v static) is unknown. + */ +NITFAPI(void) nitf_SubWindow_destruct(nitf_SubWindow ** subWindow); + + +/*! + * \fn nitf_SubWindow_setDownSampler(subWindow, downsampler, error) + * + * Bind a downsampler to the sub-window. + * \param subWindow The object + * \param downsampler A downsampler to bind to the object + * \param error An error to populate on failure + * \return NITF_SUCCESS on success, NITF_FAILURE on failure. + */ + +NITFAPI(NITF_BOOL) nitf_SubWindow_setDownSampler(nitf_SubWindow * + subWindow, + nitf_DownSampler * + downsampler, + nitf_Error * error); + +NITF_CXX_ENDGUARD + +#endif diff --git a/modules/c/nitf/include/nitf/System.h b/modules/c/nitf/include/nitf/System.h new file mode 100644 index 000000000..b068333c7 --- /dev/null +++ b/modules/c/nitf/include/nitf/System.h @@ -0,0 +1,442 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_SYSTEM_H__ +#define __NITF_SYSTEM_H__ + +#ifdef WIN32 +# if defined(NITF_MODULE_EXPORTS) +# ifndef NRT_MODULE_EXPORTS +# define NRT_MODULE_EXPORTS +# endif +# elif defined(NITF_MODULE_IMPORTS) +# ifndef NRT_MODULE_IMPORTS +# define NRT_MODULE_IMPORTS +# endif +# endif +#endif + +/******************************************************************************/ +/* DEFINES */ +/******************************************************************************/ +#include "nrt/Defines.h" +#define NITF_C NRT_C +#define NITF_GUARD NRT_GUARD +#define NITF_ENDGUARD NRT_ENDGUARD +#define NITF_BOOL NRT_BOOL +#define NITFAPI(RT) NRTAPI(RT) +#define NITFPROT(RT) NRTPROT(RT) +#define NITF_ATO32 NRT_ATO32 +#define NITF_ATOU32 NRT_ATOU32 +#define NITF_ATOU32_BASE NRT_ATOU32_BASE +#define NITF_ATO64 NRT_ATO64 +#define NITF_SNPRINTF NRT_SNPRINTF +#define NITF_VSNPRINTF NRT_VSNPRINTF +#define NITF_CXX_GUARD NRT_CXX_GUARD +#define NITF_CXX_ENDGUARD NRT_CXX_ENDGUARD +#define NITFPRIV NRTPRIV +#define NITF_FILE NRT_FILE +#define NITF_LINE NRT_LINE +#define NITF_FUNC NRT_FUNC + + +/******************************************************************************/ +/* DEBUG */ +/******************************************************************************/ +#ifdef NITF_DEBUG + #define NRT_DEBUG 1 +#endif +#include "nrt/Debug.h" +#ifdef NITF_DEBUG + #define NITF_MEM_LOG NRT_MEM_LOG + #define nitf_Debug_malloc nrt_Debug_malloc + #define nitf_Debug_realloc nrt_Debug_realloc + #define nitf_Debug_free nrt_Debug_free +#endif +#define nitf_Debug_flogf nrt_Debug_flogf + +/******************************************************************************/ +/* MEMORY */ +/******************************************************************************/ +#include "nrt/Memory.h" +#define NITF_MALLOC NRT_MALLOC +#define NITF_REALLOC NRT_REALLOC +#define NITF_FREE NRT_FREE + + +/******************************************************************************/ +/* TYPES */ +/******************************************************************************/ +#include "nrt/Types.h" +typedef nrt_Uint8 nitf_Uint8; +typedef nrt_Uint16 nitf_Uint16; +typedef nrt_Uint32 nitf_Uint32; +typedef nrt_Uint64 nitf_Uint64; +typedef nrt_Int8 nitf_Int8; +typedef nrt_Int16 nitf_Int16; +typedef nrt_Int32 nitf_Int32; +typedef nrt_Int64 nitf_Int64; +typedef nrt_IOHandle nitf_IOHandle; +typedef NRT_NATIVE_DLL NITF_NATIVE_DLL; +typedef NRT_DLL_FUNCTION_PTR NITF_DLL_FUNCTION_PTR; +typedef nrt_AccessFlags nitf_AccessFlags; +typedef nrt_CreationFlags nitf_CreationFlags; +typedef nrt_Off nitf_Off; + +#define NITF_MAX_PATH NRT_MAX_PATH +#define NITF_DEFAULT_PERM NRT_DEFAULT_PERM +#define NITF_INVALID_HANDLE_VALUE NRT_INVALID_HANDLE_VALUE +#define NITF_INVALID_HANDLE NRT_INVALID_HANDLE +#define NITF_SEEK_CUR NRT_SEEK_CUR +#define NITF_SEEK_SET NRT_SEEK_SET +#define NITF_SEEK_END NRT_SEEK_END +#define NITF_CREATE NRT_CREATE +#define NITF_OPEN_EXISTING NRT_OPEN_EXISTING +#define NITF_TRUNCATE NRT_TRUNCATE +#define NITF_ACCESS_READONLY NRT_ACCESS_READONLY +#define NITF_ACCESS_WRITEONLY NRT_ACCESS_WRITEONLY +#define NITF_ACCESS_READWRITE NRT_ACCESS_READWRITE +#define NITF_INT64 NRT_INT64 +#define NITF_SUCCESS NRT_SUCCESS +#define NITF_FAILURE NRT_FAILURE + +typedef nrt_CornersType nitf_CornersType; +#define NITF_CORNERS_UNKNOWN NRT_CORNERS_UNKNOWN +#define NITF_CORNERS_UTM NRT_CORNERS_UTM +#define NITF_CORNERS_UTM_UPS_S NRT_CORNERS_UTM_UPS_S +#define NITF_CORNERS_UTM_UPS_N NRT_CORNERS_UTM_UPS_N +#define NITF_CORNERS_GEO NRT_CORNERS_GEO +#define NITF_CORNERS_DECIMAL NRT_CORNERS_DECIMAL + +#define nitf_System_swap16 nrt_System_swap16 +#define nitf_System_swap32 nrt_System_swap32 +#define nitf_System_swap64 nrt_System_swap64 +#define nitf_System_swap64c nrt_System_swap64c + +#define NITF_NTOHS NRT_NTOHS +#define NITF_HTONS NRT_HTONS +#define NITF_NTOHL NRT_NTOHL +#define NITF_HTONL NRT_HTONL +#define NITF_HTONLL NRT_HTONLL +#define NITF_NTOHLL NRT_NTOHLL +#define NITF_HTONLC NRT_HTONLC +#define NITF_NTOHLC NRT_NTOHLC + + +/******************************************************************************/ +/* ERROR */ +/******************************************************************************/ +#include "nrt/Error.h" +#define NITF_MAX_EMESSAGE NRT_MAX_EMESSAGE +#define NITF_CTXT NRT_CTXT + +#define NITF_ERRNO NRT_ERRNO +#define NITF_STRERROR NRT_STRERROR + +#define NITF_NO_ERR NRT_NO_ERR +#define NITF_ERR_MEMORY NRT_ERR_MEMORY +#define NITF_ERR_OPENING_FILE NRT_ERR_OPENING_FILE +#define NITF_ERR_READING_FROM_FILE NRT_ERR_READING_FROM_FILE +#define NITF_ERR_SEEKING_IN_FILE NRT_ERR_SEEKING_IN_FILE +#define NITF_ERR_WRITING_TO_FILE NRT_ERR_WRITING_TO_FILE +#define NITF_ERR_STAT_FILE NRT_ERR_STAT_FILE +#define NITF_ERR_LOADING_DLL NRT_ERR_LOADING_DLL +#define NITF_ERR_UNLOADING_DLL NRT_ERR_UNLOADING_DLL +#define NITF_ERR_RETRIEVING_DLL_HOOK NRT_ERR_RETRIEVING_DLL_HOOK +#define NITF_ERR_UNINITIALIZED_DLL_READ NRT_ERR_UNINITIALIZED_DLL_READ +#define NITF_ERR_INVALID_PARAMETER NRT_ERR_INVALID_PARAMETER +#define NITF_ERR_INVALID_OBJECT NRT_ERR_INVALID_OBJECT +#define NITF_ERR_INVALID_FILE NRT_ERR_INVALID_FILE +#define NITF_ERR_COMPRESSION NRT_ERR_COMPRESSION +#define NITF_ERR_DECOMPRESSION NRT_ERR_DECOMPRESSION +#define NITF_ERR_PARSING_FILE NRT_ERR_PARSING_FILE +#define NITF_ERR_INT_STACK_OVERFLOW NRT_ERR_INT_STACK_OVERFLOW +#define NITF_ERR_UNK NRT_ERR_UNK + +typedef nrt_Error nitf_Error; + +#define nitf_Error_init nrt_Error_init +#define nitf_Error_flogf nrt_Error_flogf +#define nitf_Error_fprintf nrt_Error_fprintf +#define nitf_Error_initf nrt_Error_initf +#define nitf_Error_print nrt_Error_print + + +/******************************************************************************/ +/* DLL */ +/******************************************************************************/ +#include "nrt/DLL.h" +#define NITF_DLL_EXTENSION NRT_DLL_EXTENSION +typedef nrt_DLL nitf_DLL; +#define nitf_DLL_construct nrt_DLL_construct +#define nitf_DLL_destruct nrt_DLL_destruct +#define nitf_DLL_load nrt_DLL_load +#define nitf_DLL_unload nrt_DLL_unload +#define nitf_DLL_retrieve nrt_DLL_retrieve +#define nitf_DLL_isValid nrt_DLL_isValid + + +/******************************************************************************/ +/* SYNC */ +/******************************************************************************/ +#include "nrt/Sync.h" +#define nitf_Mutex nrt_Mutex +#define NITF_MUTEX_INIT NRT_MUTEX_INIT +#define nitf_Mutex_lock nrt_Mutex_lock +#define nitf_Mutex_unlock nrt_Mutex_unlock +#define nitf_Mutex_init nrt_Mutex_init +#define nitf_Mutex_delete nrt_Mutex_delete + + +/******************************************************************************/ +/* DIRECTORY */ +/******************************************************************************/ +#include "nrt/Directory.h" +typedef nrt_Directory nitf_Directory; +#define nitf_Directory_construct nrt_Directory_construct +#define nitf_Directory_findFirstFile nrt_Directory_findFirstFile +#define nitf_Directory_findNextFile nrt_Directory_findNextFile +#define nitf_Directory_destruct nrt_Directory_destruct +#define nitf_Directory_exists nrt_Directory_exists + + +/******************************************************************************/ +/* IOHANDLE */ +/******************************************************************************/ +#include "nrt/IOHandle.h" +#define NITF_IO_SUCCESS NRT_IO_SUCCESS +#define NITF_MAX_READ_ATTEMPTS NRT_MAX_READ_ATTEMPTS + +#define nitf_IOHandle_create nrt_IOHandle_create +#define nitf_IOHandle_read nrt_IOHandle_read +#define nitf_IOHandle_write nrt_IOHandle_write +#define nitf_IOHandle_seek nrt_IOHandle_seek +#define nitf_IOHandle_tell nrt_IOHandle_tell +#define nitf_IOHandle_getSize nrt_IOHandle_getSize +#define nitf_IOHandle_close nrt_IOHandle_close + + +/******************************************************************************/ +/* IOINTERFACE */ +/******************************************************************************/ +#include "nrt/IOInterface.h" + +typedef NRT_IO_INTERFACE_READ NITF_IO_INTERFACE_READ; +typedef NRT_IO_INTERFACE_WRITE NITF_IO_INTERFACE_WRITE; +typedef NRT_IO_INTERFACE_CAN_SEEK NITF_IO_INTERFACE_CAN_SEEK; +typedef NRT_IO_INTERFACE_SEEK NITF_IO_INTERFACE_SEEK; +typedef NRT_IO_INTERFACE_TELL NITF_IO_INTERFACE_TELL; +typedef NRT_IO_INTERFACE_GET_SIZE NITF_IO_INTERFACE_GET_SIZE; +typedef NRT_IO_INTERFACE_GET_MODE NITF_IO_INTERFACE_GET_MODE; +typedef NRT_IO_INTERFACE_CLOSE NITF_IO_INTERFACE_CLOSE; +typedef NRT_IO_INTERFACE_DESTRUCT NITF_IO_INTERFACE_DESTRUCT; + +typedef nrt_IIOInterface nitf_IIOInterface; +typedef nrt_IOInterface nitf_IOInterface; + +#define nitf_IOInterface_read nrt_IOInterface_read +#define nitf_IOInterface_write nrt_IOInterface_write +#define nitf_IOInterface_canSeek nrt_IOInterface_canSeek +#define nitf_IOInterface_seek nrt_IOInterface_seek +#define nitf_IOInterface_tell nrt_IOInterface_tell +#define nitf_IOInterface_getSize nrt_IOInterface_getSize +#define nitf_IOInterface_getMode nrt_IOInterface_getMode +#define nitf_IOInterface_close nrt_IOInterface_close +#define nitf_IOInterface_destruct nrt_IOInterface_destruct +#define nitf_IOHandleAdapter_construct nrt_IOHandleAdapter_construct +#define nitf_IOHandleAdapter_open nrt_IOHandleAdapter_open +#define nitf_BufferAdapter_construct nrt_BufferAdapter_construct + + +/******************************************************************************/ +/* DATETIME */ +/******************************************************************************/ +#include "nrt/DateTime.h" +#define NITF_DATE_FORMAT_20 "%d%H%M%SZ%b%y" +#define NITF_DATE_FORMAT_21 "%Y%m%d%H%M%S" + +typedef nrt_DateTime nitf_DateTime; +#define nitf_DateTime_now nrt_DateTime_now +#define nitf_DateTime_fromMillis nrt_DateTime_fromMillis +#define nitf_DateTime_setYear nrt_DateTime_setYear +#define nitf_DateTime_setMonth nrt_DateTime_setMonth +#define nitf_DateTime_setDayOfMonth nrt_DateTime_setDayOfMonth +#define nitf_DateTime_setDayOfWeek nrt_DateTime_setDayOfWeek +#define nitf_DateTime_setDayOfYear nrt_DateTime_setDayOfYear +#define nitf_DateTime_setHour nrt_DateTime_setHour +#define nitf_DateTime_setMinute nrt_DateTime_setMinute +#define nitf_DateTime_setSecond nrt_DateTime_setSecond +#define nitf_DateTime_setTimeInMillis nrt_DateTime_setTimeInMillis +#define nitf_DateTime_fromString nrt_DateTime_fromString +#define nitf_DateTime_destruct nrt_DateTime_destruct +#define nitf_DateTime_format nrt_DateTime_format +#define nitf_DateTime_formatMillis nrt_DateTime_formatMillis + + +/******************************************************************************/ +/* PAIR */ +/******************************************************************************/ +#include "nrt/Pair.h" +typedef nrt_Pair nitf_Pair; +#define nitf_Pair_init nrt_Pair_init +#define nitf_Pair_copy nrt_Pair_copy + + +/******************************************************************************/ +/* LIST */ +/******************************************************************************/ +#include "nrt/List.h" +typedef nrt_ListNode nitf_ListNode; +typedef NRT_DATA_ITEM_CLONE NITF_DATA_ITEM_CLONE; +typedef nrt_ListIterator nitf_ListIterator; +typedef nrt_List nitf_List; + +#define nitf_ListNode_construct nrt_ListNode_construct +#define nitf_ListNode_destruct nrt_ListNode_destruct +#define nitf_List_isEmpty nrt_List_isEmpty +#define nitf_List_pushFront nrt_List_pushFront +#define nitf_List_pushBack nrt_List_pushBack +#define nitf_List_popFront nrt_List_popFront +#define nitf_List_popBack nrt_List_popBack +#define nitf_List_construct nrt_List_construct +#define nitf_List_clone nrt_List_clone +#define nitf_List_destruct nrt_List_destruct +#define nitf_List_begin nrt_List_begin +#define nitf_List_at nrt_List_at +#define nitf_ListIterator_equals nrt_ListIterator_equals +#define nitf_ListIterator_notEqualTo nrt_ListIterator_notEqualTo +#define nitf_List_end nrt_List_end +#define nitf_List_insert nrt_List_insert +#define nitf_List_remove nrt_List_remove +#define nitf_List_move nrt_List_move +#define nitf_List_size nrt_List_size +#define nitf_List_get nrt_List_get +#define nitf_ListIterator_increment nrt_ListIterator_increment +#define nitf_ListIterator_get nrt_ListIterator_get + + +/******************************************************************************/ +/* HASHTABLE */ +/******************************************************************************/ +#include "nrt/HashTable.h" +#define NITF_TRE_HASH_SIZE 8 + +#define NITF_DATA_RETAIN_OWNER NRT_DATA_RETAIN_OWNER +#define NITF_DATA_ADOPT NRT_DATA_ADOPT + +typedef nrt_HashTable nitf_HashTable; +typedef NRT_HASH_FUNCTION NITF_HASH_FUNCTION; +typedef NRT_HASH_FUNCTOR NITF_HASH_FUNCTOR; +typedef nrt_HashTableIterator nitf_HashTableIterator; + +#define nitf_HashTable_construct nrt_HashTable_construct +#define nitf_HashTable_clone nrt_HashTable_clone +#define nitf_HashTable_setPolicy nrt_HashTable_setPolicy +#define nitf_HashTable_remove nrt_HashTable_remove +#define nitf_HashTable_initDefaults nrt_HashTable_initDefaults +#define nitf_HashTable_destruct nrt_HashTable_destruct +#define nitf_HashTable_exists nrt_HashTable_exists +#define nitf_HashTable_print nrt_HashTable_print +#define nitf_HashTable_foreach nrt_HashTable_foreach +#define nitf_HashTable_insert nrt_HashTable_insert +#define nitf_HashTable_find nrt_HashTable_find +#define nitf_HashTableIterator_equals nrt_HashTableIterator_equals +#define nitf_HashTableIterator_notEqualTo nrt_HashTableIterator_notEqualTo +#define nitf_HashTable_begin nrt_HashTable_begin +#define nitf_HashTable_end nrt_HashTable_end +#define nitf_HashTableIterator_increment nrt_HashTableIterator_increment +#define nitf_HashTableIterator_get nrt_HashTableIterator_get + + +/******************************************************************************/ +/* INTSTACK */ +/******************************************************************************/ +#include "nrt/IntStack.h" +typedef nrt_IntStack nitf_IntStack; + +#define nitf_IntStack_construct nrt_IntStack_construct +#define nitf_IntStack_clone nrt_IntStack_clone +#define nitf_IntStack_destruct nrt_IntStack_destruct +#define nitf_IntStack_top nrt_IntStack_top +#define nitf_IntStack_push nrt_IntStack_push +#define nitf_IntStack_pop nrt_IntStack_pop +#define nitf_IntStack_depth nrt_IntStack_depth + +#define NITF_INT_STACK_DEPTH NRT_INT_STACK_DEPTH + + +/******************************************************************************/ +/* TREE */ +/******************************************************************************/ +#include "nrt/Tree.h" +typedef nrt_TreeNode nitf_TreeNode; +typedef nrt_Tree nitf_Tree; + +#define nitf_TreeNode_construct nrt_TreeNode_construct +#define nitf_TreeNode_destruct nrt_TreeNode_destruct +#define nitf_TreeNode_addChild nrt_TreeNode_addChild +#define nitf_TreeNode_hasChildren nrt_TreeNode_hasChildren +#define nitf_TreeNode_removeChild nrt_TreeNode_removeChild +#define nitf_TreeNode_clone nrt_TreeNode_clone +#define nitf_Tree_construct nrt_Tree_construct +#define nitf_Tree_destruct nrt_Tree_destruct + +typedef nrt_Traversal nitf_Traversal; +#define NITF_PRE_ORDER NRT_PRE_ORDER +#define NITF_POST_ORDER NRT_POST_ORDER +typedef NRT_TREE_TRAVERSER NITF_TREE_TRAVERSER; +#define nitf_Tree_walk nrt_Tree_walk +#define nitf_Tree_clone nrt_Tree_clone + + +/******************************************************************************/ +/* UTILS */ +/******************************************************************************/ +#include "nrt/Utils.h" +#define nitf_Utils_splitString nrt_Utils_splitString +#define nitf_Utils_isNumeric nrt_Utils_isNumeric +#define nitf_Utils_isAlpha nrt_Utils_isAlpha +#define nitf_Utils_isBlank nrt_Utils_isBlank +#define nitf_Utils_trimString nrt_Utils_trimString +#define nitf_Utils_replace nrt_Utils_replace +#define nitf_Utils_baseName nrt_Utils_baseName +#define nitf_Utils_parseDecimalString nrt_Utils_parseDecimalString +#define nitf_Utils_getCurrentTimeMillis nrt_Utils_getCurrentTimeMillis +#define nitf_Utils_strncasecmp nrt_Utils_strncasecmp +#define nitf_Utils_decimalToGeographic nrt_Utils_decimalToGeographic +#define nitf_Utils_geographicToDecimal nrt_Utils_geographicToDecimal +#define nitf_Utils_parseGeographicString nrt_Utils_parseGeographicString +#define nitf_Utils_geographicLatToCharArray nrt_Utils_geographicLatToCharArray +#define nitf_Utils_geographicLonToCharArray nrt_Utils_geographicLonToCharArray +#define nitf_Utils_decimalLatToCharArray nrt_Utils_decimalLatToCharArray +#define nitf_Utils_decimalLonToCharArray nrt_Utils_decimalLonToCharArray +#define nitf_Utils_decimalLatToGeoCharArray nrt_Utils_decimalLatToGeoCharArray +#define nitf_Utils_decimalLonToGeoCharArray nrt_Utils_decimalLonToGeoCharArray +#define nitf_Utils_cornersTypeAsCoordRep nrt_Utils_cornersTypeAsCoordRep + +/******************************************************************************/ +/* NITRO-SPECIFIC DEFINES/TYPES */ +/******************************************************************************/ +#include "nitf/Defines.h" +#include "nitf/Types.h" + +#endif diff --git a/modules/c/nitf/include/nitf/TRE.h b/modules/c/nitf/include/nitf/TRE.h new file mode 100644 index 000000000..bbd42f146 --- /dev/null +++ b/modules/c/nitf/include/nitf/TRE.h @@ -0,0 +1,436 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_TRE_H__ +#define __NITF_TRE_H__ + +#include "nitf/System.h" +#include "nitf/Field.h" +#include "nitf/TREDescription.h" + +/*! + * Pass this into the id of nitf_TRE_construct to bypass the plug-in registry, + * yet still create the TRE type expected. + */ +#define NITF_TRE_RAW "raw_data" + +#define NITF_MAX_TAG 32 +#define NITF_ETAG_SZ 6 +#define NITF_EL_SZ 5 + + +/** This is used in the constructor, to specify + * that you want to use the default length for + * the TRE + */ +#define NITF_TRE_DEFAULT_LENGTH 0 + +/** If the length field of a TREDescription contains this value, + * it means that the field should be computed based on a previous field value. + * Any field that uses this for its length MUST be preceded by a NITF_COMP_LEN + * field. + */ +#define NITF_TRE_CONDITIONAL_LENGTH -100 + +/** This is used in the TRE Descriptions, for the length field + * if we want the rest of the data to fill the current field + */ +#define NITF_TRE_GOBBLE -1 + + +NITF_CXX_GUARD + + + +/* Control values that are put in the TREDescription data_type field */ +enum +{ + NITF_LOOP = NITF_BINARY + 1, /*!< data_type control loop */ + NITF_ENDLOOP, /*!< data_type control end loop */ + NITF_IF, /*!< data_type control if */ + NITF_ENDIF, /*!< data_type control endif */ + NITF_COMP_LEN, /*!< data_type computes the length of the next field */ + NITF_END /*!< data_type end marker */ +}; + +/* This can be used if the user wants to loop a constant number of times */ +/* Set the TREDescription label to NITF_CONST_N, and the number in the tag */ +/* Example: {NITF_LOOP, 0, NITF_CONST_N, "4096"} */ +#define NITF_CONST_N "CONSTANT" /*!< TREDescription label value */ +#define NITF_FUNCTION "FUNCTION" + +struct _nitf_Record; + +struct _nitf_TREHandler; +/*! + * The TRE structure, which contains the description of the TRE, as well as + * the Field data. + */ +typedef struct _nitf_TRE +{ + struct _nitf_TREHandler* handler; /*! The plug-in handler */ + NITF_DATA* priv; /*! Private data the plug-in knows about */ + char tag[NITF_MAX_TAG + 1]; /* the TRE tag */ +} nitf_TRE; + + +struct _nitf_TREEnumerator; + +/*! + * Increments the TREEnumerator and returns the data + */ +typedef nitf_Pair* (*NITF_TRE_ITERATOR_INCREMENT)(struct _nitf_TREEnumerator*, + nitf_Error*); + +/*! + * Returns a boolean stating whether or not the enumerator has more elements + */ +typedef NITF_BOOL (*NITF_TRE_ITERATOR_HAS_NEXT)(struct _nitf_TREEnumerator**); + +/** + * Returns the description/label of the current/last field retrieved from + * the enumerator. Returns NULL (and sets the error) if no description exists. + */ +typedef const char* (*NITF_TRE_ITERATOR_GET_DESCRIPTION)( + struct _nitf_TREEnumerator*, nitf_Error*); + + +typedef struct _nitf_TREEnumerator +{ + NITF_TRE_ITERATOR_INCREMENT next; + NITF_TRE_ITERATOR_HAS_NEXT hasNext; + NITF_TRE_ITERATOR_GET_DESCRIPTION getFieldDescription; + NITF_DATA* data; +} nitf_TREEnumerator; + +#define NITF_TRE_END NULL + +/*! + * The plug-in is allowed to do some initialization to prepare the TRE + * \param tre The TRE to initialize + * \param id An optional ID used to further specify a specific version, etc. + * \param error The error object + * \return NITF_FAILURE if an error occurred, otherwise NITF_SUCCESS + */ +typedef NITF_BOOL (*NITF_TRE_INIT) (nitf_TRE* tre, + const char* id, + nitf_Error * error); + +/*! + * Retrieves the id of the TRE. This could be the same value as the TRE tag, + * any other identifier, or NULL. + * \param tre The TRE + * \return the ID, or NULL of no ID is set + */ +typedef const char* (*NITF_TRE_ID_GET) (nitf_TRE* tre); + +/*! + * Read data from the given IO interface, parsing it + * however the plug-in desires. + * \param io The IO interface we are reading from + * \param length The length of the TRE (i.e. # of bytes to read) + * \param tre The associated TRE + * \param record The associated Record object + * \param error The error object + * \return NITF_FAILURE if an error occurred, otherwise NITF_SUCCESS + */ +typedef NITF_BOOL (*NITF_TRE_READER)(nitf_IOInterface* io, + nitf_Uint32 length, + nitf_TRE *tre, + struct _nitf_Record *record, + nitf_Error *error); + + +/*! + * Returns a nitf_List* of Fields that match the input XPath-like pattern. + * \param tre The associated TRE + * \param pattern The XPath pattern used to search for fields + * \param error The error object + * \return nitf_List* of fields, or NULL if an error occurred + */ +typedef nitf_List* (*NITF_TRE_FIND)(nitf_TRE * tre, + const char *pattern, + nitf_Error* error); + + +/*! + * Sets a field in the given TRE. It is up to the plug-in to + * \param tre The associated TRE + * \param tag The name of the field + * \param data The data (void*) to set the field to + * \param dataLength The size of the data + * \param error The error object + * \return NITF_FAILURE if an error occurred, otherwise NITF_SUCCESS + */ +typedef NITF_BOOL (*NITF_TRE_FIELD_SET)(nitf_TRE * tre, + const char *tag, + NITF_DATA * data, + size_t dataLength, + nitf_Error * error); + +/*! + * Returns the one Field with the given tag ID + * \param tre The associated TRE + * \param tag The tag, or name of the field to return + * \return the nitf_Field*, or NULL if it doesn't exist (or error) + */ +typedef nitf_Field* (*NITF_TRE_FIELD_GET)(nitf_TRE * tre, + const char *tag); + +/*! + * Sets a field in the given TRE. It is up to the plug-in to + * \param io The IO interface to write to + * \param tre The associated TRE to write + * \param record The associated Record object + * \param error The error object + * \return NITF_FAILURE if an error occurred, otherwise NITF_SUCCESS + */ +typedef NITF_BOOL (*NITF_TRE_WRITER)(nitf_IOInterface* io, + nitf_TRE* tre, + struct _nitf_Record* record, + nitf_Error *error); + +/*! + * Returns the current size of the TRE. + * \param tre The associated TRE + * \param error The error object + * \return The size of the TRE, or -1 if an error occurred + */ +typedef int (*NITF_TRE_SIZE)(nitf_TRE *tre, nitf_Error *error); + +/*! + * Sets a field in the given TRE. It is up to the plug-in to + * \param source The source TRE to clone + * \param dest The destination TRE, where the source will be cloned to + * \param error The error object + * \return NITF_FAILURE if an error occurred, otherwise NITF_SUCCESS + */ +typedef NITF_BOOL (*NITF_TRE_CLONE)(nitf_TRE *source, + nitf_TRE *dest, + nitf_Error *error); + +/*! + * Destroy any internal data associated with the given TRE. You should not + * destroy the TRE. It will be deleted by the library. + * \param tre The associated TRE + */ +typedef void (*NITF_TRE_DESTRUCT)(nitf_TRE*); + +/*! + * Returns a nitf_TREEnumerator for the TRE + * \param tre The associated TRE + * \param error The error object + * \return an enumerator, or NULL if an error occurred + */ +typedef nitf_TREEnumerator* (*NITF_TRE_ITERATOR)(nitf_TRE *tre, + nitf_Error *error); + + +/*! + * \brief The TRE Handler Interface + * + * This interface should be fulfilled by any plug-in that wants to handle a TRE. + * View the documentation above for each of the methods below. + * In addition to the methods, there is an optional data field (of type + * NITF_DATA*) which allows the plug-in to store data associated with the + * Handler. + * + */ +typedef struct _nitf_TREHandler +{ + /* The init method gets called when creating a TRE from scratch */ + NITF_TRE_INIT init; + + /* Get the name/id of the TRE. This is NOT the tag, however it may be the + * same value as the tag. The id is used to identify a specific + * version/incarnation of the TRE, if multiple are possible. For most TREs, + * this value will be the same as the tag. + */ + NITF_TRE_ID_GET getID; + + /* The read method gets called when reading a TRE from an IO interface */ + NITF_TRE_READER read; + + /* setField is called by the setField proxy of the TRE API */ + NITF_TRE_FIELD_SET setField; + + /* getField is called by the getField proxy of the TRE API */ + NITF_TRE_FIELD_GET getField; + + /* find is called by the find proxy of the TRE API */ + NITF_TRE_FIND find; + + /* write gets called when writing the TRE to an output IO interface */ + NITF_TRE_WRITER write; + + /* begin is called by the begin proxy of the TRE API */ + NITF_TRE_ITERATOR begin; + + /* getCurrentSize is called by the getCurrentSize proxy of the TRE API */ + NITF_TRE_SIZE getCurrentSize; + + /* clone is called when a TRE is cloned */ + NITF_TRE_CLONE clone; + + /* + * destruct is called when a TRE is destroyed - NOT when the handler is. + * destruct is an optional operation and doesn't need to be provided by + * plug-in implementations + */ + NITF_TRE_DESTRUCT destruct; + + /* optional data that contains handler-wide data for supporting TREs of + * the type that the plug-in handles + */ + NITF_DATA* data; +} nitf_TREHandler; + + +/*! + * Construct a TRE Skeleton (for Reader). + * and the offset within the file + * \param tag The name of the TRE + * \param error The error to populate on failure + * \return The newly constructed TRE + * + */ +NITFPROT(nitf_TRE *) nitf_TRE_createSkeleton(const char* tag, + nitf_Error * error); + +/*! + * Construct an actual TRE (for users of the library) + * \param tag Name of TRE + * \param id Optional identifier used to specify a specific + * version/incarnation of the TRE (if several are possible). + * \param error Error to populate if something bad happens + * \return A new TRE or NULL on failure + */ +NITFAPI(nitf_TRE *) nitf_TRE_construct(const char* tag, + const char* id, + nitf_Error * error); + + + +/*! + * Clone this object. This is a deep copy operation. + * This is a serious problem since this is the first thing + * people will want to do. Possible solution: put desc inside + * of the TRE. Alternate possibility: call TRE plugin + * handler explicitly + * \param source The source object + * \param error An error to populate upon failure + * \return A new object that is identical to the old + */ +NITFAPI(nitf_TRE *) nitf_TRE_clone(nitf_TRE * tre, nitf_Error * error); + + +/*! + * Destroy the TRE. + * \param tre The tre to destroy + */ +NITFAPI(void) nitf_TRE_destruct(nitf_TRE ** tre); + + +/*! + * Returns 1 if the given tag exists in the TRE + * \param tre the TRE + * \param tag the tag we want to check for existence + * \return 1 on success, 0 on failure + */ +NITFAPI(NITF_BOOL) nitf_TRE_exists(nitf_TRE * tre, const char *tag); + + +/*! + * Sets the field for the given tag in the tre + * If the field was never set, a new field is created + * If the field already existed, the old one is updated + * \param tre the TRE + * \param tag the tag we want to check for existence + * \param data the data to store in the field + * \param dataLength the length of the data + * \param error The error to populate on failure + * \return 1 on success, 0 on failure + */ +NITFAPI(NITF_BOOL) nitf_TRE_setField(nitf_TRE * tre, + const char *tag, + NITF_DATA * data, + size_t dataLength, + nitf_Error * error); + +/*! + * This function retrieves all fields that match the pattern. Exactly + * how and what patterns are supported is up to the plug-in -- here + * we are simply an interface broker, making plug-in capabilities exposed + * to our users. In TREUtils, our default behavior is to find any + * fields with an occurence of the string. For XML TREs, we assume that + * the user will be building an XPath expression, and that a plug-in should + * support that capability. + * + * \since 2.0 + * \param tre The TRE + * \param A pattern to match + * \param error The error if one occurs + * \return A nitf_List of nitf_Pair*, or NULL if no matches + * \todo How to tell if its an error or failure to retrieve -- probably + * need another parameter + * + */ +NITFAPI(nitf_List*) nitf_TRE_find(nitf_TRE* tre, + const char* pattern, + nitf_Error* error); + + +/*! + * + * Gets a field by its (exact) name. The retrieval is here for basic + * symmetry and to prevent the application developer from playing with + * the model directly. We really want them to have an opaque view of + * the TREs internals + * \todo What about the error? + * + * \since 2.0 + * + * \param tre The TRE + * \param tag The tag name + * \return Return NULL if no such field exists in the TRE, otherwise, the value + */ +NITFAPI(nitf_Field*) nitf_TRE_getField(nitf_TRE* tre, + const char* tag); + + +NITFAPI(nitf_TREEnumerator*) nitf_TRE_begin(nitf_TRE* tre, nitf_Error* error); + + +NITFAPI(int) nitf_TRE_getCurrentSize(nitf_TRE* tre, nitf_Error* error); + +/*! + * Returns the ID of the TRE. This is optional and is allowed to be NULL. The + * ID is only useful when you want to identify how the TRE is structured. + * Depending on how the TRE is created (via its handler), this name/ID can + * be used to keep track of its origin. + */ +NITFAPI(const char*) nitf_TRE_getID(nitf_TRE* tre); + + +NITF_CXX_ENDGUARD + +#endif diff --git a/modules/c/nitf/include/nitf/TRECursor.h b/modules/c/nitf/include/nitf/TRECursor.h new file mode 100644 index 000000000..23210e127 --- /dev/null +++ b/modules/c/nitf/include/nitf/TRECursor.h @@ -0,0 +1,114 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_TRE_CURSOR_H__ +#define __NITF_TRE_CURSOR_H__ + +#include "nitf/TRE.h" +#include "nitf/TREDescription.h" + +NITF_CXX_GUARD +/*! + * A structure for keeping track of the + * state of the TRE Description when processing it + * + * This is currently public, but it may be a good idea + * to move everything related to the nitf_TRECursor + * out of the public realm. + */ +typedef struct _nitf_TRECursor +{ + /* DO NOT TOUCH THESE! */ + int numItems; /* holds the number of descPtr items */ + int index; /* holds the current index to process */ + int looping; /* keeps track of how deep we are in the loops */ + nitf_IntStack *loop; /* holds loopcount for each level of loops */ + nitf_IntStack *loop_idx; /* holds the indexes for each level of loops (arrays) */ + nitf_IntStack *loop_rtn; /* holds the endloop bookmark for each level of loops */ + nitf_TRE *tre; /* the TRE associated with this cursor */ + nitf_TREDescription *end_ptr; /* holds a pointer to the end description */ + + /* YOU CAN REFER TO THE MEMBERS BELOW IN YOUR CODE */ + nitf_TREDescription *prev_ptr; /* holds the previous description */ + nitf_TREDescription *desc_ptr; /* pointer to the current nitf_TREDescription */ + char tag_str[256]; /* holds the fully qualified tag name of the current tag */ + int length; /* the length of the field + * This should be used over the TREDescription length because + * the field may need to be computed. This will contain the + * actual, possibly computed length. */ +} +nitf_TRECursor; + + +/*! + * Initializes the cursor + * + * \param tre The input TRE + * \return A cursor for the TRE + */ +NITFAPI(nitf_TRECursor) nitf_TRECursor_begin(nitf_TRE * tre); + + +/*! + * Returns NITF_BOOL value noting if the cursor has reached the end + * + * \param tre_cursor The TRECursor + * \return 1 if done, 0 otherwise + */ +NITFAPI(NITF_BOOL) nitf_TRECursor_isDone(nitf_TRECursor * tre_cursor); + + +/*! + * Cleans up any allocated members of the TRECursor + * This should be called when finished with an cursor + * + * \param tre_cursor The TRECursor + * \return 1 if done, 0 otherwise + */ +NITFAPI(void) nitf_TRECursor_cleanup(nitf_TRECursor * tre_cursor); + +/*! + * Duplicates the input cursor. This can be useful if you want to capture a + * snapshot of the cursor to revert back to. + * + * \param tre The input TRE cursor + * \return A duplicated cursor for the TRE + */ +NITFAPI(nitf_TRECursor) nitf_TRECursor_clone(nitf_TRECursor *tre_cursor, + nitf_Error * error); + + +/*! + * Iterate to the next tag in the TRE. + * + * \param tre_cursor The cursor to use + * \param error The error to populate on failure + * \return NITF_SUCCESS on sucess or NITF_FAILURE otherwise + */ +NITFAPI(int) nitf_TRECursor_iterate(nitf_TRECursor * tre_cursor, + nitf_Error * error); + + +NITF_CXX_ENDGUARD + +#endif + diff --git a/modules/c/nitf/include/nitf/TREDescription.h b/modules/c/nitf/include/nitf/TREDescription.h new file mode 100644 index 000000000..a2dfcb98f --- /dev/null +++ b/modules/c/nitf/include/nitf/TREDescription.h @@ -0,0 +1,41 @@ +#ifndef __NITF_TRE_DESCRIPTION_H__ +#define __NITF_TRE_DESCRIPTION_H__ + + +/*! + * The TREDescription structure encapsulates the metadata that describes one + * field description in a TRE. + */ +typedef struct _nitf_TREDescription +{ + int data_type; /*!< the type of field */ + int data_count; /*!< the size of the field */ + char *label; /*!< description */ + char *tag; /*!< unique tag */ + char *special; /*!< special field, reserved for special cases */ +} nitf_TREDescription; + + +#define NITF_TRE_DESC_NO_LENGTH -1 + +/*! + * Information about one TREDescription object + */ +typedef struct _nitf_TREDescriptionInfo +{ + char *name; /*! The name to associate with the Description */ + nitf_TREDescription *description; /*! The TREDescription */ + int lengthMatch; /*! The length to match against TREs with; used to choose TREs */ +} nitf_TREDescriptionInfo; + +/*! + * Contains a set, or array, of TREDescriptionInfos* + */ +typedef struct _nitf_TREDescriptionSet +{ + int defaultIndex; /*! Set to the index of the default description */ + nitf_TREDescriptionInfo* descriptions; +} nitf_TREDescriptionSet; + + +#endif diff --git a/modules/c/nitf/include/nitf/TREPrivateData.h b/modules/c/nitf/include/nitf/TREPrivateData.h new file mode 100644 index 000000000..fc7b9a0de --- /dev/null +++ b/modules/c/nitf/include/nitf/TREPrivateData.h @@ -0,0 +1,65 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_TRE_PRIVATE_DATA_H__ +#define __NITF_TRE_PRIVATE_DATA_H__ + +#include "nitf/TRE.h" +#include "nitf/TREDescription.h" + +NITF_CXX_GUARD + + +/*! + * A structure meant to be used for the private data of the TRE structure. + * It keeps track of the length (if given) as well as the Description + */ +typedef struct _nitf_TREPrivateData +{ + nitf_Uint32 length; + char* descriptionName; /* the name/ID of the TREDescription */ + nitf_TREDescription* description; + nitf_HashTable *hash; + NITF_DATA *userData; /*! user-defined - meant for extending this */ +} nitf_TREPrivateData; + + +NITFAPI(nitf_TREPrivateData *) nitf_TREPrivateData_construct( + nitf_Error * error); + +NITFAPI(nitf_TREPrivateData *) nitf_TREPrivateData_clone( + nitf_TREPrivateData *source, nitf_Error * error); + +NITFAPI(void) nitf_TREPrivateData_destruct(nitf_TREPrivateData **priv); + +NITFPROT(NITF_BOOL) nitf_TREPrivateData_flush(nitf_TREPrivateData *priv, + nitf_Error * error); + +NITFPROT(NITF_BOOL) nitf_TREPrivateData_setDescriptionName( + nitf_TREPrivateData *priv, const char* name, nitf_Error * error); + + + +NITF_CXX_ENDGUARD + +#endif + diff --git a/modules/c/nitf/include/nitf/TREUtils.h b/modules/c/nitf/include/nitf/TREUtils.h new file mode 100644 index 000000000..01047d9bb --- /dev/null +++ b/modules/c/nitf/include/nitf/TREUtils.h @@ -0,0 +1,105 @@ +#ifndef __NITF_TRE_UTILS_H__ +#define __NITF_TRE_UTILS_H__ + +#include "nitf/TREDescription.h" +#include "nitf/TRE.h" +#include "nitf/TRECursor.h" +#include "nitf/TREPrivateData.h" + +NITF_CXX_GUARD + +NITFAPI(int) nitf_TREUtils_computeLength(nitf_TRE * tre); + +NITFAPI(NITF_BOOL) nitf_TREUtils_setDescription(nitf_TRE* tre, + nitf_Uint32 length, + nitf_Error* error); + +NITFAPI(NITF_BOOL) nitf_TREUtils_fillData(nitf_TRE * tre, + const nitf_TREDescription* descrip, + nitf_Error * error); + +NITFAPI(NITF_BOOL) nitf_TREUtils_setValue(nitf_TRE * tre, + const char *tag, + NITF_DATA * data, + size_t dataLength, nitf_Error * error); + +NITFAPI(NITF_BOOL) nitf_TREUtils_readField(nitf_IOInterface* io, + char *fld, + int length, + nitf_Error * error); + +NITFAPI(char *) nitf_TREUtils_getRawData(nitf_TRE * tre, + nitf_Uint32* treLength, + nitf_Error * error); + +NITFAPI(NITF_BOOL) nitf_TREUtils_isSane(nitf_TRE * tre); + +/*! + * Spit out the TRE for debugging purposes + * \param tre The TRE + * \param desc_ptr The TRE description + * \param error The error to populate on failure + * \return One on success, zero on failure + */ +NITFAPI(int) nitf_TREUtils_print(nitf_TRE * tre, nitf_Error * error); + +NITFAPI(int) nitf_TREUtils_parse(nitf_TRE * tre, + char *bufptr, + nitf_Error * error); + +NITFAPI(nitf_TREHandler*) + nitf_TREUtils_createBasicHandler(nitf_TREDescriptionSet* set, + nitf_TREHandler *handler, + nitf_Error* error); + +/*! + * The "basic" functions used by the basic handler. + * If you're creating your own handler, you can use these for the functions + * that you don't need to override + */ + +NITFAPI(NITF_BOOL) nitf_TREUtils_basicInit(nitf_TRE * tre, + const char* id, + nitf_Error * error); + +NITFAPI(const char*) nitf_TREUtils_basicGetID(nitf_TRE *tre); + +NITFAPI(NITF_BOOL) nitf_TREUtils_basicRead(nitf_IOInterface* io, + nitf_Uint32 length, + nitf_TRE* tre, + struct _nitf_Record* record, + nitf_Error* error); + +NITFAPI(NITF_BOOL) nitf_TREUtils_basicSetField(nitf_TRE* tre, + const char* tag, + NITF_DATA* data, + size_t dataLength, + nitf_Error* error); + +NITFAPI(nitf_Field*) nitf_TREUtils_basicGetField(nitf_TRE* tre, + const char* tag); + +NITFAPI(nitf_List*) nitf_TREUtils_basicFind(nitf_TRE* tre, + const char* pattern, + nitf_Error* error); + +NITFAPI(NITF_BOOL) nitf_TREUtils_basicWrite(nitf_IOInterface* io, + nitf_TRE* tre, + struct _nitf_Record* record, + nitf_Error* error); + +NITFAPI(nitf_TREEnumerator*) nitf_TREUtils_basicBegin(nitf_TRE* tre, + nitf_Error* error); + +NITFAPI(int) nitf_TREUtils_basicGetCurrentSize(nitf_TRE* tre, + nitf_Error* error); + +NITFAPI(NITF_BOOL) nitf_TREUtils_basicClone(nitf_TRE *source, + nitf_TRE *tre, + nitf_Error *error); + +NITFAPI(void) nitf_TREUtils_basicDestruct(nitf_TRE* tre); + +NITF_CXX_ENDGUARD + +#endif diff --git a/modules/c/nitf/include/nitf/TextSegment.h b/modules/c/nitf/include/nitf/TextSegment.h new file mode 100644 index 000000000..d4436b727 --- /dev/null +++ b/modules/c/nitf/include/nitf/TextSegment.h @@ -0,0 +1,77 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_TEXT_SEGMENT_H__ +#define __NITF_TEXT_SEGMENT_H__ + +#include "nitf/System.h" +#include "nitf/TextSubheader.h" + + +NITF_CXX_GUARD + +/*! + * \struct nitf_TextSegment + * \brief ... + * + * The TextSegment object contains the sub-objects that + * ... + */ +typedef struct _nitf_TextSegment +{ + nitf_TextSubheader *subheader; + nitf_Uint64 offset; + nitf_Uint64 end; +} +nitf_TextSegment; + + +/*! + * Construct a new header. This simply produces an empty + * subheader + * + * \param error + * \return An text header + */ +NITFAPI(nitf_TextSegment *) nitf_TextSegment_construct(nitf_Error * error); + + +/*! + * Clone this object. This is a deep copy operation. + * + * \param source The source object + * \param error An error to populate upon failure + * \return A new object that is identical to the old + */ +NITFAPI(nitf_TextSegment *) +nitf_TextSegment_clone(nitf_TextSegment * source, nitf_Error * error); + +/*! + * Destruct an text subheader, and NULL-set it + * \param segment An text segment + */ +NITFAPI(void) nitf_TextSegment_destruct(nitf_TextSegment ** segment); + + +NITF_CXX_ENDGUARD + +#endif diff --git a/modules/c/nitf/include/nitf/TextSubheader.h b/modules/c/nitf/include/nitf/TextSubheader.h new file mode 100644 index 000000000..a299e8979 --- /dev/null +++ b/modules/c/nitf/include/nitf/TextSubheader.h @@ -0,0 +1,108 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_TEXT_SUBHEADER_H__ +#define __NITF_TEXT_SUBHEADER_H__ + +/* We get file security and some constants already */ +/* defined by including this first */ +#include "nitf/FileHeader.h" + +#define NITF_TE_SZ 2 +#define NITF_TEXTID_SZ 7 +#define NITF_TXTALVL_SZ 3 +#define NITF_TXTDT_SZ 14 +#define NITF_TXTITL_SZ 80 +#define NITF_TSCLAS_SZ 1 +#define NITF_TXTFMT_SZ 3 +#define NITF_TE filePartType +#define NITF_TEXTID textID +#define NITF_TXTALVL attachmentLevel +#define NITF_TXTDT dateTime +#define NITF_TXTITL title +#define NITF_TSCLAS securityClass +#define NITF_TXTFMT format +#define NITF_TXSHDL_SZ 5 +#define NITF_TXSOFL_SZ 3 +#define NITF_TXSHDL extendedHeaderLength +#define NITF_TXSOFL extendedHeaderOverflow + +NITF_CXX_GUARD + +/*! + * TODO: Add documentation + */ +typedef struct _nitf_TextSubheader +{ + nitf_Field *filePartType; + nitf_Field *textID; + nitf_Field *attachmentLevel; + nitf_Field *dateTime; + nitf_Field *title; + nitf_Field *securityClass; + nitf_FileSecurity *securityGroup; + nitf_Field *encrypted; + nitf_Field *format; + + nitf_Field *extendedHeaderLength; + nitf_Field *extendedHeaderOverflow; + + /* This section (unfortunately), has an extendedSection */ + nitf_Extensions *extendedSection; + +} +nitf_TextSubheader; + + +/*! + * Construct a new text subheader object. This object will + * be null set for every field. The object returned will be + * a full-fledged subheader, unless there is an error, in which + * case NULL will be returned, and the error object that was + * passed in will be populated. + * + * \param error In case of error, when this function returns, this + * parameter will be populated + * + * \return The text subheader, or NULL on failure. + */ +NITFAPI(nitf_TextSubheader *) +nitf_TextSubheader_construct(nitf_Error * error); + +/*! + * TODO: Add documentation + */ +NITFAPI(nitf_TextSubheader *) +nitf_TextSubheader_clone(nitf_TextSubheader * source, nitf_Error * error); + +/*! + * Destroy a text subheader object, and NULL-set the subheader. + * A double pointer is make the NULL-set persistant on function + * exit. + * + * \param The address of the the text subheader pointer + */ +NITFAPI(void) nitf_TextSubheader_destruct(nitf_TextSubheader ** subhdr); + +NITF_CXX_ENDGUARD + +#endif diff --git a/modules/c/nitf/include/nitf/Types.h b/modules/c/nitf/include/nitf/Types.h new file mode 100644 index 000000000..33542a519 --- /dev/null +++ b/modules/c/nitf/include/nitf/Types.h @@ -0,0 +1,40 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_TYPES_H__ +#define __NITF_TYPES_H__ + +/* Enum for the supported version types */ +typedef enum _nitf_Version +{ + NITF_VER_20 = 100, + NITF_VER_21, + NITF_VER_UNKNOWN +} nitf_Version; + +/* These macros check the NITF Version */ +#define IS_NITF20(V) ((V) == NITF_VER_20) +#define IS_NITF21(V) ((V) == NITF_VER_21) + + +typedef void NITF_DATA; +#endif diff --git a/modules/c/nitf/include/nitf/WriteHandler.h b/modules/c/nitf/include/nitf/WriteHandler.h new file mode 100644 index 000000000..dfb2ff2c3 --- /dev/null +++ b/modules/c/nitf/include/nitf/WriteHandler.h @@ -0,0 +1,65 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_WRITE_HANDLER_H__ +#define __NITF_WRITE_HANDLER_H__ + +#include "nitf/System.h" + +NITF_CXX_GUARD + +/* + * Function pointer for writing. + * \param data The ancillary "helper" data + * \param io The output interface + * \param error populated on error + */ +typedef NITF_BOOL(*NITF_IWRITEHANDLER_WRITE)(NITF_DATA *data, + nitf_IOInterface* output, nitf_Error *error); + +/* + * Function pointer for destructing the data structure + * \param data The ancillary "helper" data + */ +typedef void (*NITF_IWRITEHANDLER_DESTRUCT)(NITF_DATA *); + +/*! + * \struct nitf_IWriteHandler + * \brief The "write handler" interface, which handles writing data + */ +typedef struct _nitf_IWriteHandler +{ + NITF_IWRITEHANDLER_WRITE write; + NITF_IWRITEHANDLER_DESTRUCT destruct; +} nitf_IWriteHandler; + +typedef struct _nitf_WriteHandler +{ + nitf_IWriteHandler *iface; + NITF_DATA *data; +} nitf_WriteHandler; + +NITFAPI(void) nitf_WriteHandler_destruct(nitf_WriteHandler **writeHandler); + +NITF_CXX_ENDGUARD + +#endif diff --git a/modules/c/nitf/include/nitf/Writer.h b/modules/c/nitf/include/nitf/Writer.h new file mode 100644 index 000000000..e76b45cd9 --- /dev/null +++ b/modules/c/nitf/include/nitf/Writer.h @@ -0,0 +1,178 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_WRITER_H__ +#define __NITF_WRITER_H__ + +#include "nitf/PluginRegistry.h" +#include "nitf/Record.h" +#include "nitf/ImageIO.h" +#include "nitf/ImageWriter.h" +#include "nitf/SegmentWriter.h" +#include "nitf/ComplexityLevel.h" + +NITF_CXX_GUARD + +/*! + * \struct nitf_Writer + * \brief This object represents the 2.1 (2.0?) file writer + */ +typedef struct _nitf_Writer +{ + nitf_List *warningList; + nitf_WriteHandler **imageWriters; + nitf_WriteHandler **textWriters; + nitf_WriteHandler **graphicWriters; + nitf_WriteHandler **dataExtensionWriters; + nitf_IOInterface* output; + nitf_Record *record; + int numImageWriters; + int numTextWriters; + int numGraphicWriters; + int numDataExtensionWriters; + NITF_BOOL ownOutput; +} +nitf_Writer; + + +/* ------------------------------------------------------------------ */ +/* PUBLIC PROTOTYPES */ +/* ------------------------------------------------------------------ */ + +/*! + * Construct a new writer + * \param error A populated structure upon failure + * \return A Writer, or NULL on failure + */ +NITFAPI(nitf_Writer *) nitf_Writer_construct(nitf_Error * error); + +/*! + * Destroy a writer, set *writer to NULL + * \param writer The writer to NULL-set + */ +NITFAPI(void) nitf_Writer_destruct(nitf_Writer ** writer); + +NITFAPI(NITF_BOOL) nitf_Writer_prepare(nitf_Writer * writer, + nitf_Record * record, + nitf_IOHandle ioHandle, + nitf_Error * error); + + + +NITFAPI(NITF_BOOL) nitf_Writer_prepareIO(nitf_Writer * writer, + nitf_Record * record, + nitf_IOInterface* io, + nitf_Error * error); + + +/*! + * Sets the WriteHandler for the Image at the given index. + */ +NITFAPI(NITF_BOOL) nitf_Writer_setImageWriteHandler(nitf_Writer *writer, + int index, nitf_WriteHandler *writeHandler, nitf_Error * error); + +/*! + * Sets the WriteHandler for the Graphic at the given index. + */ +NITFAPI(NITF_BOOL) nitf_Writer_setGraphicWriteHandler(nitf_Writer *writer, + int index, nitf_WriteHandler *writeHandler, nitf_Error * error); + +/*! + * Sets the WriteHandler for the Text at the given index. + */ +NITFAPI(NITF_BOOL) nitf_Writer_setTextWriteHandler(nitf_Writer *writer, + int index, nitf_WriteHandler *writeHandler, nitf_Error * error); + +/*! + * Sets the WriteHandler for the DE Segment at the given index. + */ +NITFAPI(NITF_BOOL) nitf_Writer_setDEWriteHandler(nitf_Writer *writer, + int index, nitf_WriteHandler *writeHandler, nitf_Error * error); + + +/*! + * Creates and returns a new ImageWriter for the image at the given index. + * This is deprecated, but is available for backwards compatibility. + * + * \param writer The Writer object + * \param options + * \param index The segment index + * + * \deprecated - setImageWriteHandler is the preferred method to use. + * \return A new ImageWriter, or NULL on failure + */ +NITFAPI(nitf_ImageWriter *) nitf_Writer_newImageWriter(nitf_Writer* writer, + int index, + nrt_HashTable* options, + nitf_Error* error); + +/*! + * Creates and returns a new SegmentWriter for the graphic at the given index. + * This is deprecated, but is available for backwards compatibility. + * + * \param writer The Writer object + * \param index The segment index + * + * \deprecated - setGraphicWriteHandler is the preferred method to use. + * \return A new SegmentWriter, or NULL on failure + */ +NITFAPI(nitf_SegmentWriter*) nitf_Writer_newGraphicWriter(nitf_Writer *writer, + int index, nitf_Error * error); + +/*! + * Creates and returns a new SegmentWriter for the text at the given index. + * This is deprecated, but is available for backwards compatibility. + * + * \param writer The Writer object + * \param index The segment index + * + * \deprecated - setTextWriteHandler is the preferred method to use. + * \return A new SegmentWriter, or NULL on failure + */ +NITFAPI(nitf_SegmentWriter*) nitf_Writer_newTextWriter(nitf_Writer *writer, + int index, nitf_Error * error); + +/*! + * Creates and returns a new SegmentWriter for the DESegment at the given index. + * This is deprecated, but is available for backwards compatibility. + * + * \param writer The Writer object + * \param index The segment index + * + * \deprecated - setDEWriteHandler is the preferred method to use. + * \return A new SegmentWriter, or NULL on failure + */ +NITFAPI(nitf_SegmentWriter*) nitf_Writer_newDEWriter(nitf_Writer *writer, + int index, nitf_Error * error); + + +/*! + * Performs the write operation + * + * \return NITF_SUCCESS or NITF_FAILURE + */ +NITFAPI(NITF_BOOL) nitf_Writer_write(nitf_Writer * writer, nitf_Error * error); + + +NITF_CXX_ENDGUARD + +#endif diff --git a/modules/c/nitf/include/nitf/WriterOptions.h b/modules/c/nitf/include/nitf/WriterOptions.h new file mode 100644 index 000000000..f9d431ba5 --- /dev/null +++ b/modules/c/nitf/include/nitf/WriterOptions.h @@ -0,0 +1,36 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2013, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NITF_WRITER_OPTIONS_H__ +#define __NITF_WRITER_OPTIONS_H__ + +#include "nitf/System.h" + +NITF_CXX_GUARD + +#define C8_COMPRESSION_RATIO_KEY "compressionRatio" +#define C8_NUM_RESOLUTIONS_KEY "numResolutions" + +NITF_CXX_ENDGUARD + +#endif + diff --git a/modules/c/nitf/shared/ACCHZB.c b/modules/c/nitf/shared/ACCHZB.c new file mode 100644 index 000000000..c277c087c --- /dev/null +++ b/modules/c/nitf/shared/ACCHZB.c @@ -0,0 +1,49 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_N, 2, "Number of horizontal accuracy regions", "NUMACHZ", }, + {NITF_LOOP, 0, NULL, "NUMACHZ"}, + {NITF_BCS_A, 3, "Unit of Measure for AAH", "UNIAAH" }, + {NITF_IF, 0, "ne ", "UNIAAH"}, + {NITF_BCS_N, 5, "Absolute Horizontal Accuracy", "AAH" }, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_BCS_A, 3, "Unit of Measure for APH", "UNIAPH" }, + {NITF_IF, 0, "ne ", "UNIAPH"}, + {NITF_BCS_N, 5, "Point-to-Point Horizontal Accuracy", "APH" }, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_BCS_N, 3, "Number of Points in Bounding Polygon", "NUMPTS" }, + {NITF_LOOP, 0, NULL, "NUMPTS"}, + {NITF_BCS_N, 15, "Longitude/Easting", "LON" }, + {NITF_BCS_N, 15, "Latitude/Northing", "LAT" }, + {NITF_ENDLOOP, 0, NULL, NULL}, + {NITF_ENDLOOP, 0, NULL, NULL}, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(ACCHZB, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/ACCPOB.c b/modules/c/nitf/shared/ACCPOB.c new file mode 100644 index 000000000..174f084ea --- /dev/null +++ b/modules/c/nitf/shared/ACCPOB.c @@ -0,0 +1,50 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_N, 2, "Number of positional accuracy regions", + "NUMACPO" }, + {NITF_LOOP, 0, NULL, "NUMACPO"}, + {NITF_BCS_A, 3, "Unit of Measure for AAH", "UNIAAH" }, + {NITF_BCS_N, 5, "Absolute Horizontal Accuracy", "AAH" }, + {NITF_BCS_A, 3, "Unit of Measure for AAV", "UNIAAV" }, + {NITF_BCS_N, 5, "Absolute Vertical Accuracy", "AAV" }, + {NITF_BCS_A, 3, "Unit of Measure for APH", "UNIAPH" }, + {NITF_BCS_N, 5, "Point-to-Point Horizontal Accuracy", "APH" }, + {NITF_BCS_A, 3, "Unit of Measure for APV", "UNIAPV" }, + {NITF_BCS_N, 5, "Point-to-Point Vertical Accuracy", "APV" }, + {NITF_BCS_N, 3, "Number of Points in Bounding Polygon", "NUMPTS" }, + {NITF_LOOP, 0, NULL, "NUMPTS"}, + {NITF_BCS_N, 15, "Longitude/Easting", "LON" }, + {NITF_BCS_N, 15, "Latitude/Northing", "LAT" }, + {NITF_ENDLOOP, 0, NULL, NULL}, + {NITF_ENDLOOP, 0, NULL, NULL}, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(ACCPOB, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/ACCVTB.c b/modules/c/nitf/shared/ACCVTB.c new file mode 100644 index 000000000..cc299c43b --- /dev/null +++ b/modules/c/nitf/shared/ACCVTB.c @@ -0,0 +1,51 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_N, 2, "Number of vertical accuracy regions", + "NUMACVT" }, + {NITF_LOOP, 0, NULL, "NUMACVT"}, + {NITF_BCS_A, 3, "Unit of Measure for AAV", "UNIAAV" }, + {NITF_IF, 0, "ne ", "UNIAAV"}, + {NITF_BCS_N, 5, "Absolute Vertical Accuracy", "AAV" }, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_BCS_A, 3, "Unit of Measure for APV", "UNIAPV" }, + {NITF_IF, 0, "ne ", "UNIAPV"}, + {NITF_BCS_N, 5, "Point-to-Point Vertical Accuracy", "APV" }, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_BCS_N, 3, "Number of Points in Bounding Polygon", + "NUMPTS" }, + {NITF_LOOP, 0, NULL, "NUMPTS"}, + {NITF_BCS_N, 15, "Longitude/Easting", "LON" }, + {NITF_BCS_N, 15, "Latitude/Northing", "LAT" }, + {NITF_ENDLOOP, 0, NULL, NULL}, + {NITF_ENDLOOP, 0, NULL, NULL}, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(ACCVTB, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/ACFTA.c b/modules/c/nitf/shared/ACFTA.c new file mode 100644 index 000000000..f9bb17fc6 --- /dev/null +++ b/modules/c/nitf/shared/ACFTA.c @@ -0,0 +1,145 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + +NITF_CXX_GUARD + + /* from ACFTA ver 1.0 */ +static nitf_TREDescription descrip_00132[] = { + {NITF_BCS_A, 10, "Aircraft Mission ID", "AC_MSN_ID" }, + {NITF_BCS_A, 1, "Scene Type", "SCTYPE" }, + {NITF_BCS_A, 4, "Scene No.", "SCNUM"}, + {NITF_BCS_A, 3, "Sensor ID", "SENSOR_ID"}, + {NITF_BCS_A, 4, "Total No. of Patches", "PATCH_TOT"}, + {NITF_BCS_A, 3, "Total No. of MTI Packets", "MTI_TOT"}, + {NITF_BCS_A, 7, "Processing Date", "PDATE"}, + {NITF_BCS_A, 3, "Immediate Scene Host", "IMHOSTNO"}, + {NITF_BCS_A, 5, "Immediate Scene Req ID", "IMREQID"}, + {NITF_BCS_A, 1, "Scene Source", "SCENE_SOURCE"}, + {NITF_BCS_A, 2, "Mission Plan Mode", "MPLAN"}, + {NITF_BCS_A, 21, "Entry Location", "ENTLOC"}, + {NITF_BCS_A, 6, "Entry Altitude", "ENTALT"}, + {NITF_BCS_A, 21, "Exit Location", "EXITLOC"}, + {NITF_BCS_A, 6, "Exit Altitude", "EXITALT"}, + {NITF_BCS_A, 7, "True Map Angle", "TMAP"}, + {NITF_BCS_A, 3, "RCS Calibration Coef.", "RCS"}, + {NITF_BCS_A, 7, "Row Spacing", "ROW_SPACING"}, + {NITF_BCS_A, 7, "Col Spacing", "COL_SPACING"}, + {NITF_BCS_A, 4, "Sensor Serial No.", "SENSERIAL"}, + {NITF_BCS_A, 7, "Airborne SW Version", "ABSWVER"}, + {NITF_END, 0, NULL, NULL} +}; + + /* from draft ACFTA ver 0.9a */ +static nitf_TREDescription descrip_00154[] = { + {NITF_BCS_A, 10, "Aircraft Mission ID", "AC_MSN_ID"}, + {NITF_BCS_A, 10, "Aircraft Tail Number", "AC_TAIL_NO"}, + {NITF_BCS_A, 10, "Sensor ID", "SENSOR_ID"}, + {NITF_BCS_A, 1, "Scene Source", "SCENE_SOURCE"}, + {NITF_BCS_A, 6, "Scene No.", "SCNUM"}, + {NITF_BCS_A, 8, "Processing Date", "PDATE"}, + {NITF_BCS_A, 6, "Immediate Scene Host", "IMHOSTNO"}, + {NITF_BCS_A, 5, "Immediate Scene Req ID", "IMREQID"}, + {NITF_BCS_A, 3, "Mission Plan Mode", "MPLAN"}, + {NITF_BCS_A, 21, "Entry Location", "ENTLOC"}, + {NITF_BCS_A, 6, "Entry Altitude", "ENTALT"}, + {NITF_BCS_A, 21, "Exit Location", "EXITLOC"}, + {NITF_BCS_A, 6, "Exit Altitude", "EXITALT"}, + {NITF_BCS_A, 7, "True Map Angle", "TMAP"}, + {NITF_BCS_A, 7, "Row Spacing", "ROW_SPACING"}, + {NITF_BCS_A, 7, "Col Spacing", "COL_SPACING"}, + {NITF_BCS_A, 6, "Sensor Serial No.", "SENSERIAL"}, + {NITF_BCS_A, 7, "Airborne SW Version", "ABSWVER"}, + {NITF_BCS_A, 4, "Total No. of Patches", "PATCH_TOT"}, + {NITF_BCS_A, 3, "Total No. of MTI Packets", "MTI_TOT"}, + {NITF_END, 0, NULL, NULL} +}; + + /* as found version on newly processed ASARS2 legacy images */ + /* marked ACFTA, though seems to be from a draft of ACFTB */ +static nitf_TREDescription descrip_00199[] = { + {NITF_BCS_A, 20, "Aircraft Mission ID", "AC_MSN_ID"}, + {NITF_BCS_A, 10, "Aircraft Tail Number", "AC_TAIL_NO"}, + {NITF_BCS_A, 12, "Acrft Takeoff Date/Time", "AC_TO"}, + {NITF_BCS_A, 4, "Sensor ID Type", "SENSOR_ID_TYPE"}, + {NITF_BCS_A, 6, "Sensor ID", "SENSOR_ID"}, + {NITF_BCS_N, 1, "Scene Source", "SCENE_SOURCE"}, + {NITF_BCS_N, 6, "Scene No.", "SCNUM"}, + {NITF_BCS_N, 8, "Processing Date", "PDATE"}, + {NITF_BCS_N, 6, "Immediate Scene Host", "IMHOSTNO"}, + {NITF_BCS_N, 5, "Immediate Scene Req ID", "IMREQID"}, + {NITF_BCS_N, 3, "Mission Plan Mode", "MPLAN"}, + {NITF_BCS_A, 25, "Entry Location", "ENTLOC"}, + {NITF_BCS_A, 6, "Entry Elevation", "ENTELV"}, + {NITF_BCS_A, 1, "Elevation Units", "ELVUNIT"}, + {NITF_BCS_A, 25, "Exit Location", "EXITLOC"}, + {NITF_BCS_A, 6, "Exit Elevation", "EXITELV"}, + {NITF_BCS_A, 7, "True Map Angle", "TMAP"}, + {NITF_BCS_A, 1, "spacing units?", "RESERVD1"}, + {NITF_BCS_A, 7, "Row Spacing", "ROW_SPACING"}, + {NITF_BCS_A, 7, "Col Spacing", "COL_SPACING"}, + {NITF_BCS_A, 6, "Sensor Focal Length", "FOCAL_LENGTH"}, + {NITF_BCS_A, 6, "Sensor Serial No.", "SENSERIAL" }, + {NITF_BCS_A, 7, "Airborne SW Version", "ABSWVER"}, + {NITF_BCS_A, 8, "Calibration Date", "CAL_DATE"}, + {NITF_BCS_N, 4, "Total No. of Patches", "PATCH_TOT"}, + {NITF_BCS_A, 3, "Total No. of MTI Packets", "MTI_TOT"}, + {NITF_END, 0, NULL, NULL} +}; + +/* Define the available descriptions and the default one */ +static nitf_TREDescriptionInfo descriptions[] = { + { "ACFTA_132", descrip_00132, 132 }, + { "ACFTA_154", descrip_00154, 154 }, + { "ACFTA_199", descrip_00199, 199 }, + { NULL, NULL, NITF_TRE_DESC_NO_LENGTH } +}; +static nitf_TREDescriptionSet descriptionSet = { 0, descriptions }; + + +#if 1 +NITF_DECLARE_PLUGIN(ACFTA) +#else +static const char *ident[] = { NITF_PLUGIN_TRE_KEY, "ACFTA", NULL }; + + +static nitf_TREHandler* acftaHandler = NULL; +NITFAPI(const char**) ACFTA_init(nitf_Error* error) +{ + // Init here! + acftaHandler = nitf_TREUtils_createBasicHandler(&descriptionSet, error); + if (!acftaHandler) + return NULL; + + return ident; +} + +NITFAPI(void) ACFTA_cleanup(void){} +#endif + + + + + + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/ACFTB.c b/modules/c/nitf/shared/ACFTB.c new file mode 100644 index 000000000..9f881a2b0 --- /dev/null +++ b/modules/c/nitf/shared/ACFTB.c @@ -0,0 +1,61 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_A, 20, "Aircraft Mission ID", "AC_MSN_ID" }, + {NITF_BCS_A, 10, "Aircraft Tail Number", "AC_TAIL_NO" }, + {NITF_BCS_A, 12, "Acrft Takeoff Date/Time", "AC_TO" }, + {NITF_BCS_A, 4, "Sensor ID Type", "SENSOR_ID_TYPE" }, + {NITF_BCS_A, 6, "Sensor ID", "SENSOR_ID" }, + {NITF_BCS_N, 1, "Scene Source", "SCENE_SOURCE" }, + {NITF_BCS_N, 6, "Scene No.", "SCNUM" }, + {NITF_BCS_N, 8, "Processing Date", "PDATE" }, + {NITF_BCS_N, 6, "Immediate Scene Host", "IMHOSTNO" }, + {NITF_BCS_N, 5, "Immediate Scene Req ID", "IMREQID" }, + {NITF_BCS_N, 3, "Mission Plan Mode", "MPLAN" }, + {NITF_BCS_A, 25, "Entry Location", "ENTLOC" }, + {NITF_BCS_A, 6, "Location Accuracy", "LOC_ACCY" }, + {NITF_BCS_A, 6, "Entry Elevation", "ENTELV" }, + {NITF_BCS_A, 1, "Elevation Units", "ELV_UNIT" }, + {NITF_BCS_A, 25, "Exit Location", "EXITLOC" }, + {NITF_BCS_A, 6, "Exit Elevation", "EXITELV" }, + {NITF_BCS_A, 7, "True Map Angle", "TMAP" }, + {NITF_BCS_A, 7, "Row Spacing", "ROW_SPACING" }, + {NITF_BCS_A, 1, "Row Spacing Units", "ROW_SPACING_UNITS" }, + {NITF_BCS_A, 7, "Col Spacing", "COL_SPACING" }, + {NITF_BCS_A, 1, "Col Spacing Units", "COL_SPACING_UNITS" }, + {NITF_BCS_A, 6, "Sensor Focal Length", "FOCAL_LENGTH" }, + {NITF_BCS_A, 6, "Sensor Serial No.", "SENSERIAL" }, + {NITF_BCS_A, 7, "Airborne Software Version", "ABSWVER" }, + {NITF_BCS_A, 8, "Calibration Date", "CAL_DATE" }, + {NITF_BCS_N, 4, "Total Number of Patches", "PATCH_TOT" }, + {NITF_BCS_N, 3, "Total Number of MTIRP Extensions", "MTI_TOT" }, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(ACFTB, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/AIMIDA.c b/modules/c/nitf/shared/AIMIDA.c new file mode 100644 index 000000000..05d27e0a1 --- /dev/null +++ b/modules/c/nitf/shared/AIMIDA.c @@ -0,0 +1,107 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + +NITF_CXX_GUARD + + +static nitf_TREDescription descrip_00069[] = { + {NITF_BCS_A, 7, "Aircraft T.O. Date", "MISSION_DATE" }, + {NITF_BCS_A, 4, "Mission ID", "MISSION_NO" }, + {NITF_BCS_A, 2, "Flight Number", "FLIGHT_NO" }, + {NITF_BCS_A, 3, "Image Operation Number", "OP_NUM" }, + {NITF_BCS_A, 2, "Start Segment ID", "START_SEGMENT" }, + {NITF_BCS_A, 2, "Reprocess Number", "REPRO_NUM" }, + {NITF_BCS_A, 3, "Replay", "REPLAY" }, + {NITF_BCS_A, 1, "Reserved 1", "RESVD001" }, + {NITF_BCS_A, 2, "Starting Tile Column", "START_COLUMN" }, + {NITF_BCS_A, 5, "Starting Tile Row", "START_ROW" }, + {NITF_BCS_A, 2, "Ending Segment", "END_SEGMENT" }, + {NITF_BCS_A, 2, "Ending Tile Column", "END_COLUMN" }, + {NITF_BCS_A, 5, "Ending Tile Row", "END_ROW" }, + {NITF_BCS_A, 2, "Country Code", "COUNTRY" }, + {NITF_BCS_A, 4, "Reserved 2", "RESVD002" }, + {NITF_BCS_A, 11, "Location lat/long", "LOCATION" }, + {NITF_BCS_A, 5, "Time of First Line", "TIME" }, + {NITF_BCS_A, 7, "Date of First Line", "CREATION_DATE" }, + {NITF_END, 0, NULL, NULL} +}; + + /* from draft AIMIDA vers 0.9a */ +static nitf_TREDescription descrip_00073[] = { + {NITF_BCS_A, 8, "Aircraft T.O. Date", "MISSION_DATE" }, + {NITF_BCS_A, 4, "Mission ID", "MISSION_NO" }, + {NITF_BCS_A, 2, "Flight No.", "FLIGHT_NO" }, + {NITF_BCS_A, 3, "Image Operation No.", "OP_NUM" }, + {NITF_BCS_A, 2, "Reserved 1", "RESVD001" }, + {NITF_BCS_A, 2, "Reprocess No.", "REPRO_NUM" }, + {NITF_BCS_A, 3, "Retransmission No.", "REPLAY" }, + {NITF_BCS_A, 1, "Reserved 2", "RESVD002" }, + {NITF_BCS_A, 3, "Starting Tile Column", "START_COLUMN" }, + {NITF_BCS_A, 5, "Starting Tile Row", "START_ROW" }, + {NITF_BCS_A, 2, "Reserved 3", "RESVD003" }, + {NITF_BCS_A, 3, "Ending Tile Column", "END_COLUMN" }, + {NITF_BCS_A, 5, "Ending Tile Row", "END_ROW" }, + {NITF_BCS_A, 2, "Country Code", "COUNTRY" }, + {NITF_BCS_A, 4, "Reserved 4", "RESVD004" }, + {NITF_BCS_A, 11, "Location lat/long", "LOCATION" }, + {NITF_BCS_A, 5, "Time of First Line", "TIME" }, + {NITF_BCS_A, 8, "Date of First Line", "CREATION_DATE" }, + {NITF_END, 0, NULL, NULL} +}; + +static nitf_TREDescription descrip_00089[] = { + {NITF_BCS_A, 14, "Acquisition Date/Time", "MISSION_DATE_TIME" }, + {NITF_BCS_A, 4, "Mission Number", "MISSION_NO" }, + {NITF_BCS_A, 10, "Mission ID (ATO)", "MISSION_ID" }, + {NITF_BCS_A, 2, "Flight No.", "FLIGHT_NO" }, + {NITF_BCS_N, 3, "Image Operation No.", "OP_NUM" }, + {NITF_BCS_A, 2, "Current Segment ID", "CURRENT_SEGMENT" }, + {NITF_BCS_N, 2, "Reprocess No.", "REPRO_NUM" }, + {NITF_BCS_A, 3, "Retransmission No.", "REPLAY" }, + {NITF_BCS_A, 1, "reserved 1", "RESVD001" }, + {NITF_BCS_N, 3, "Starting Tile Column", "START_COLUMN" }, + {NITF_BCS_N, 5, "Starting Tile Row", "START_ROW" }, + {NITF_BCS_A, 2, "Ending Segment", "END_SEGMENT" }, + {NITF_BCS_N, 3, "Ending Tile Column", "END_COLUMN" }, + {NITF_BCS_N, 5, "Ending Tile Row", "END_ROW" }, + {NITF_BCS_A, 2, "Country Code", "COUNTRY" }, + {NITF_BCS_A, 4, "reserved 2", "RESVD002" }, + {NITF_BCS_A, 11, "Location lat/long", "LOCATION" }, + {NITF_BCS_A, 13, "reserved 3", "RESVD003" }, + {NITF_END, 0, NULL, NULL} +}; + + +/* Define the available descriptions and the default one */ +static nitf_TREDescriptionInfo descriptions[] = { + { "AIMIDA_69", descrip_00069, 69 }, + { "AIMIDA_73", descrip_00073, 73 }, + { "AIMIDA_89", descrip_00089, 89 }, + { NULL, NULL, NITF_TRE_DESC_NO_LENGTH } +}; +static nitf_TREDescriptionSet descriptionSet = { 0, descriptions }; + +NITF_DECLARE_PLUGIN(AIMIDA) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/AIMIDB.c b/modules/c/nitf/shared/AIMIDB.c new file mode 100644 index 000000000..7c05791fa --- /dev/null +++ b/modules/c/nitf/shared/AIMIDB.c @@ -0,0 +1,51 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_A, 14, "Acquisition Date/Time", "ACQUISITION_DATE" }, + {NITF_BCS_A, 4, "Mission Number", "MISSION_NO" }, + {NITF_BCS_A, 10, "Mission ID (ATO)", "MISSION_IDENTIFICATION" }, + {NITF_BCS_A, 2, "Flight No.", "FLIGHT_NO" }, + {NITF_BCS_N, 3, "Image Operation No.", "OP_NUM" }, + {NITF_BCS_A, 2, "Current Segment ID", "CURRENT_SEGMENT" }, + {NITF_BCS_N, 2, "Reprocess No.", "REPRO_NUM" }, + {NITF_BCS_A, 3, "Retransmission No.", "REPLAY" }, + {NITF_BCS_A, 1, "reserved 1", "RESERVED_001" }, + {NITF_BCS_N, 3, "Start Tile Column", "START_TILE_COLUMN" }, + {NITF_BCS_N, 5, "Start Tile Row", "START_TILE_ROW" }, + {NITF_BCS_A, 2, "End Segment", "END_SEGMENT" }, + {NITF_BCS_N, 3, "End Tile Column", "END_TILE_COLUMN" }, + {NITF_BCS_N, 5, "End Tile Row", "END_TILE_ROW" }, + {NITF_BCS_A, 2, "Country Code", "COUNTRY" }, + {NITF_BCS_A, 4, "reserved 2", "RESERVED002" }, + {NITF_BCS_A, 11, "Location lat/long", "LOCATION" }, + {NITF_BCS_A, 13, "reserved 3", "RESERVED003" }, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(AIMIDB, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/AIPBCA.c b/modules/c/nitf/shared/AIPBCA.c new file mode 100644 index 000000000..c2861fdbb --- /dev/null +++ b/modules/c/nitf/shared/AIPBCA.c @@ -0,0 +1,83 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_N, 5, "Patch Width", "Patch_Width", }, + {NITF_BCS_A, 16, "Semi-major axis (x component)", "u_hat_x" }, + {NITF_BCS_A, 16, "Semi-major axis (y component)", "u_hat_y" }, + {NITF_BCS_A, 16, "Semi-major axis (z component)", "u_hat_z" }, + + {NITF_BCS_A, 16, "Semi-minor axis (x component)", "v_hat_x" }, + {NITF_BCS_A, 16, "Semi-minor axis (y component)", "v_hat_y" }, + {NITF_BCS_A, 16, "Semi-minor axis (z component)", "v_hat_z" }, + + {NITF_BCS_A, 16, "Normal vector (x component)", "n_hat_x" }, + {NITF_BCS_A, 16, "Normal vector (y component)", "n_hat_y" }, + {NITF_BCS_A, 16, "Normal vector (z component)", "n_hat_z" }, + + {NITF_BCS_N, 7, "Cross-track depression angle", "Dep_Angle" }, + {NITF_BCS_N, 10, "Cross-track range", "CT_Track_Range" }, + + {NITF_BCS_A, 16, "Dummy param, leading edge of patch", "eta_0" }, + {NITF_BCS_A, 16, "Dummy param, trailing edge of patch", "eta_1" }, + + {NITF_BCS_A, 9, "Component u of image coords (x direction)", "x_Img_u" }, + {NITF_BCS_A, 9, "Component v of image coords (x direction)", "x_Img_v" }, + {NITF_BCS_A, 9, "Component n of image coords (x direction)", "x_Img_n" }, + + {NITF_BCS_A, 9, "Component u of image coords (y direction)", "y_Img_u" }, + {NITF_BCS_A, 9, "Component v of image coords (y direction)", "y_Img_v" }, + {NITF_BCS_A, 9, "Component n of image coords (y direction)", "y_Img_n" }, + + {NITF_BCS_A, 9, "Component u of image coords (z direction)", "z_Img_u" }, + {NITF_BCS_A, 9, "Component v of image coords (z direction)", "z_Img_v" }, + {NITF_BCS_A, 9, "Component n of image coords (z direction)", "z_Img_n" }, + + {NITF_BCS_A, 9, "Cross-track unit vector (x component)", "ct_hat_x" }, + {NITF_BCS_A, 9, "Cross-track unit vector (y component)", "ct_hat_y" }, + {NITF_BCS_A, 9, "Cross-track unit vector (z component)", "ct_hat_z" }, + + {NITF_BCS_A, 13, "Scene center line point (u component)", "scl_pt_u" }, + {NITF_BCS_A, 13, "Scene center line point (v component)", "scl_pt_v" }, + {NITF_BCS_A, 13, "Scene center line point (n component)", "scl_pt_n" }, + + {NITF_BCS_A, 13, "Semi-major axis length", "sigma_sm" }, + {NITF_BCS_A, 13, "Semi-minor axis length", "sigma_sn" }, + + {NITF_BCS_A, 10, "Small circle origin offset (along v)", "s_off" }, + {NITF_BCS_A, 12, "Offset btwn small and great circle plane", "Rn_offset" }, + + {NITF_BCS_N, 11, "Range to CRP", "CRP_Range" }, + {NITF_BCS_N, 7, "Scene ref. depression angle", "Ref_Dep_Ang" }, + {NITF_BCS_N, 9, "Scene ref. aspect angle", "Ref_Asp_Ang" }, + {NITF_BCS_N, 1, "N-skip azimuth", "n_Skip_Az" }, + {NITF_BCS_N, 1, "N-skip range", "n_Skip_Range" }, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(AIPBCA, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/ASTORA.c b/modules/c/nitf/shared/ASTORA.c new file mode 100644 index 000000000..8d2038c35 --- /dev/null +++ b/modules/c/nitf/shared/ASTORA.c @@ -0,0 +1,179 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + + {NITF_BCS_N, 6, "Number of rows in full image prod.", "IMG_TOTAL_ROWS" }, + {NITF_BCS_N, 6, "Number of columns in full image prod.", + "IMG_TOTAL_COLS" }, + + {NITF_BCS_N, 6, "Upper left corner of tile, row coord.", "IMG_INDEX_ROW" }, + {NITF_BCS_N, 6, "Upper left corner of tile, col coord.", "IMG_INDEX_COL" }, + + {NITF_BCS_A, 7, "Distance from ref. ellipsoid to MSL geoid at ref. pt.", + "GEOID_OFFSET" }, + + {NITF_BCS_A, 16, "Cone angle (radians)", "ALPHA_0" }, + + {NITF_BCS_N, 2, "Left/right look flag", "K_L" }, + + {NITF_BCS_A, 15, "Speed of light (m/s)", "C_M" }, + + {NITF_BCS_A, 16, "Nominal Aircraft Roll (radians)", "AC_ROLL" }, + + {NITF_BCS_A, 16, "Nominal Aircraft Pitch (radians)", "AC_PITCH" }, + + {NITF_BCS_A, 16, "Nominal Aircraft Yaw (radians)", "AC_YAW" }, + + {NITF_BCS_A, 16, "Nominal Aircraft Track Heading (radians)", + "AC_TRACK_HEADING" + }, + + + {NITF_BCS_A, 13, "Synthetic aperture origin point (m) (x component)", + "AP_ORIGIN_X" + }, + + + {NITF_BCS_A, 13, "Sythetic aperture origin point (m) (y component)", + "AP_ORIGIN_Y" + }, + + {NITF_BCS_A, 13, "Sythetic aperture origin point (m) (z component)", + "AP_ORIGIN_Z" + }, + + {NITF_BCS_A, 16, "Sythetic aperture direction unit vec. (x component)", + "AP_DIR_X" + }, + + + {NITF_BCS_A, 16, "Sythetic aperture direction unit vec. (y component)", + "AP_DIR_Y" + }, + + {NITF_BCS_A, 16, "Sythetic aperture direction unit vec. (z component)", + "AP_DIR_Z" + }, + + + {NITF_BCS_A, 12, "Start point of synthetic aperture", "X_AP_START" }, + {NITF_BCS_A, 12, "End point of synthetic aperture", "X_AP_END" }, + + {NITF_BCS_N, 4, "Spot stitching row shift", "SS_ROW_SHIFT" }, + {NITF_BCS_N, 4, "Spot stitching column shift", "SS_COL_SHIFT" }, + + {NITF_BCS_A, 16, "Semi-major axis (x component)", "U_hat_x" }, + {NITF_BCS_A, 16, "Semi-major axis (y component)", "U_hat_y" }, + {NITF_BCS_A, 16, "Semi-major axis (z component)", "U_hat_z" }, + + {NITF_BCS_A, 16, "Semi-minor axis (x component)", "V_hat_x" }, + {NITF_BCS_A, 16, "Semi-minor axis (y component)", "V_hat_y" }, + {NITF_BCS_A, 16, "Semi-minor axis (z component)", "V_hat_z" }, + + {NITF_BCS_A, 16, "Normal vector (x component)", "N_hat_x" }, + {NITF_BCS_A, 16, "Normal vector (y component)", "N_hat_y" }, + {NITF_BCS_A, 16, "Normal vector (z component)", "N_hat_z" }, + + {NITF_BCS_A, 16, "Dummy param, leading edge of patch", "Eta_0" }, + + {NITF_BCS_A, 13, "Semi-major axis length", "Sigma_sm" }, + {NITF_BCS_A, 13, "Semi-minor axis length", "Sigma_sn" }, + + {NITF_BCS_A, 10, + "Offset between small circle and great circle plane (m)", + "S_off" }, + + {NITF_BCS_N, 12, + "Offset between small circle and great circle plane (m)", + "Rn_offset" }, + + {NITF_BCS_N, 16, + "Radius of curvature of scene center line (m)", + "R_scl" }, + + {NITF_BCS_N, 16, + "Radius of curvature of nominal aircraft flight track (m)", + "R_nav" }, + + {NITF_BCS_N, 16, + "Cross-track offset to scene center line (m)", + "R_sc_exact" }, + + + {NITF_BCS_A, 16, + "Center of scene center line fit circle, ECEF (m) (x component)", + "C_sc_x" }, + {NITF_BCS_A, 16, + "Center of scene center line fit circle, ECEF (m) (y component)", + "C_sc_y" }, + {NITF_BCS_A, 16, + "Center of scene center line fit circle, ECEF (m) (z component)", + "C_sc_z" }, + + + {NITF_BCS_A, 16, + "Local radial direction unit vector, leading edge of patch (x component)", + "K_hat_x" }, + {NITF_BCS_A, 16, + "Local radial direction unit vector, leading edge of patch (y component)", + "K_hat_y" }, + {NITF_BCS_A, 16, + "Local radial direction unit vector, leading edge of patch (z component)", + "K_hat_z" }, + + {NITF_BCS_A, 16, + "Local along-track unit vector, leading edge of patch (x component)", + "L_hat_x" }, + {NITF_BCS_A, 16, + "Local along-track unit vector, leading edge of patch (y component)", + "L_hat_y" }, + {NITF_BCS_A, 16, + "Local along-track unit vector, leading edge of patch (z component)", + "L_hat_z" }, + + {NITF_BCS_A, 16, + "Perp. distance from nav. circle to scene center line point", + "P_Z" }, + + {NITF_BCS_A, 16, + "Perp. distance from nav. circle to scene center line point", + "Theta_c" }, + + {NITF_BCS_N, 16, + "Tangent cone apex parameter", + "Alpha_sl" }, + + {NITF_BCS_N, 16, + "Tangent cone scale parameter", + "Sigma_tc" }, + + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(ASTORA, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/BANDSA.c b/modules/c/nitf/shared/BANDSA.c new file mode 100644 index 000000000..b4d7055fe --- /dev/null +++ b/modules/c/nitf/shared/BANDSA.c @@ -0,0 +1,50 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_A, 7, "ROW_SPACING", "ROW_SPACING" }, + {NITF_BCS_A, 1, "ROW_SPACING_UNITS", "ROW_SPACING_UNITS" }, + {NITF_BCS_A, 7, "COL_SPACING", "COL_SPACING" }, + {NITF_BCS_A, 1, "COL_SPACING_UNITS", "COL_SPACING_UNITS" }, + {NITF_BCS_A, 6, "FOCAL_LENGTH", "FOCAL_LENGTH" }, + {NITF_BCS_N, 4, "BANDCOUNT", "BANDCOUNT" }, + {NITF_LOOP, 0, NULL, "BANDCOUNT"}, + {NITF_BCS_A, 5, "BANDPEAK", "BANDPEAK" }, + {NITF_BCS_A, 5, "BANDLBOUND", "BANDLBOUND" }, + {NITF_BCS_A, 5, "BANDUBOUND", "BANDUBOUND" }, + {NITF_BCS_A, 5, "BANDWIDTH", "BANDWIDTH" }, + {NITF_BCS_A, 6, "BANDCALDRK", "BANDCALDRK" }, + {NITF_BCS_A, 5, "BANDCALINC", "BANDCALINC" }, + {NITF_BCS_A, 5, "BANDRESP", "BANDRESP" }, + {NITF_BCS_A, 5, "BANDASD", "BANDASD" }, + {NITF_BCS_A, 5, "BANDGSD", "BANDGSD" }, + {NITF_ENDLOOP, 0, NULL, NULL }, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(BANDSA, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/BANDSB.c b/modules/c/nitf/shared/BANDSB.c new file mode 100644 index 000000000..ca92677a0 --- /dev/null +++ b/modules/c/nitf/shared/BANDSB.c @@ -0,0 +1,175 @@ + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_N, 5, "Number of Bands", "COUNT" }, + {NITF_BCS_A, 24, "Data Representation", "RADIOMETRIC_QUANTITY" }, + {NITF_BCS_A, 1, "Data Representation Unit", "RADIOMETRIC_QUANTITY_UNIT" }, + {NITF_BINARY, 4, "Cube Scale Factor", "SCALE_FACTOR" }, + {NITF_BINARY, 4, "Cube Additive Factor", "ADDITIVE_FACTOR" }, + {NITF_BCS_N, 7, "Row Ground Sample Distance", "ROW_GSD" }, + {NITF_BCS_A, 1, "Units of Row Ground Sample Distance", "ROW_GSD_UNIT" }, + {NITF_BCS_N, 7, "Column Ground Sample Distance", "COL_GSD" }, + {NITF_BCS_A, 1, "Units of Column Ground Sample Distance", "COL_GSD_UNIT" }, + {NITF_BCS_N, 7, "Spatial Response Function (Rows)", "SPT_RESP_ROW" }, + {NITF_BCS_A, 1, "Units of Spatial Response Function (Rows)", "SPT_RESP_UNIT_ROW" }, + {NITF_BCS_N, 7, "Spatial Response Function (Cols)", "SPT_RESP_COL" }, + {NITF_BCS_A, 1, "Units of Spatial Response Function (Cols)", "SPT_RESP_UNIT_COL" }, + {NITF_BINARY,48, "Field reserved for future use", "DATA_FLD_1" }, + {NITF_BINARY, 4, "Bit-wise Existence Mask Field", "EXISTENCE_MASK" }, + {NITF_IF, 0, "& 0x80000000", "EXISTENCE_MASK" }, + {NITF_BCS_A, 24, "Adjustment Surface", "RADIOMETRIC_ADJUSTMENT_SURFACE" }, + {NITF_BINARY, 4, "Adjustment Altitude Above WGS84 Ellipsoid", "ATMOSPHERIC_ADJUSTMENT_ALTITUDE" }, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "& 0x40000000", "EXISTENCE_MASK" }, + {NITF_BCS_N, 7, "Diameter of the lens", "DIAMETER" }, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "& 0x20000000", "EXISTENCE_MASK" }, + {NITF_BINARY,32, "Field reserved for future use", "DATA_FLD_2" }, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "& 0x01F80000", "EXISTENCE_MASK" }, + {NITF_BCS_A, 1, "Wave Length Units", "WAVE_LENGTH_UNIT" }, + {NITF_ENDIF, 0, NULL, NULL}, + + {NITF_LOOP, 0, NULL, "COUNT" }, + + {NITF_IF, 0, "& 0x10000000", "EXISTENCE_MASK" }, + {NITF_BCS_A, 50, "Band n Identifier", "BANDID" }, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "& 0x08000000", "EXISTENCE_MASK" }, + {NITF_BCS_N, 1, "Bad Band Flag", "BAD_BAND" }, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "& 0x04000000", "EXISTENCE_MASK" }, + {NITF_BCS_N, 3, "NIIRS Value", "NIIRS" }, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "& 0x02000000", "EXISTENCE_MASK" }, + {NITF_BCS_N, 5, "Band n Focal length", "FOCAL_LEN" }, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "& 0x01000000", "EXISTENCE_MASK" }, + {NITF_BCS_N, 7, "Band n Center Response Wavelength", "CWAVE" }, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "& 0x00800000", "EXISTENCE_MASK" }, + {NITF_BCS_N, 7, "Band n Width", "FWHM" }, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "& 0x00400000", "EXISTENCE_MASK" }, + {NITF_BCS_N, 7, "Band n Width Uncertainty", "FWHM_UNC" }, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "& 0x00200000", "EXISTENCE_MASK" }, + {NITF_BCS_N, 7, "Band n Nominal Wavelength", "NOM_WAVE" }, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "& 0x00100000", "EXISTENCE_MASK" }, + {NITF_BCS_N, 7, "Band n Nominal Wavelength Uncertainty", "NOM_WAVE_UNC" }, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "& 0x00080000", "EXISTENCE_MASK" }, + {NITF_BCS_N, 7, "Band n Lower Wavelength Bound", "LBOUND" }, + {NITF_BCS_N, 7, "Band n Upper Wavelength Bound", "UBOUND" }, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "& 0x00040000", "EXISTENCE_MASK" }, + {NITF_BINARY, 4, "Individual Scale Factor", "SCALE_FACTOR" }, + {NITF_BINARY, 4, "Individual Additive Factor", "ADDITIVE_FACTOR" }, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "& 0x00020000", "EXISTENCE_MASK" }, + {NITF_BCS_A, 16, "Start Time", "START_TIME" }, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "& 0x00010000", "EXISTENCE_MASK" }, + {NITF_BCS_N, 6, "Integration Time", "INT_TIME" }, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "& 0x00008000", "EXISTENCE_MASK" }, + {NITF_BCS_N, 6, "Band n Calibration (Dark)", "CALDRK" }, + {NITF_BCS_N, 5, "Band n Calibration (Increment)", "CALIBRATION_SENSITIVITY" }, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "& 0x00004000", "EXISTENCE_MASK" }, + {NITF_BCS_N, 7, "Band n Spatial Response Interval (Row)", "ROW_GSD" }, + {NITF_IF, 0, "& 0x00002000", "EXISTENCE_MASK" }, + {NITF_BCS_N, 7, "Band n Spatial Response Interval Uncertainty (Row)", "ROW_GSD_UNC" }, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_BCS_A, 1, "Unit of Row Spacing", "ROW_GSD_UNIT" }, + {NITF_BCS_N, 7, "Band n Spatial Response Interval (Col)", "COL_GSD" }, + {NITF_IF, 0, "& 0x00002000", "EXISTENCE_MASK" }, + {NITF_BCS_N, 7, "Band n Spatial Response Interval Uncertainty (Col)", "COL_GSD_UNC" }, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_BCS_A, 1, "Unit of Column Spacing", "COL_GSD_UNIT" }, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "& 0x00001000", "EXISTENCE_MASK" }, + {NITF_BCS_N, 5, "Band n Background Noise", "BKNOISE" }, + {NITF_BCS_N, 5, "Band n Scene Noise", "SCNNOISE" }, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "& 0x00000800", "EXISTENCE_MASK" }, + {NITF_BCS_N, 7, "Band n Spatial Response Function (Row)", "SPT_RESP_FUNCTION_ROW" }, + {NITF_IF, 0, "& 0x00000400", "EXISTENCE_MASK" }, + {NITF_BCS_N, 7, "Band n Spatial Response Function Uncertainty (Row)", "SPT_RESP_UNC_ROW" }, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_BCS_A, 1, "Unit of Spatial Response (Row)", "SPT_RESP_UNIT_ROW" }, + {NITF_BCS_N, 7, "Band n Spatial Response Function (Col)", "SPT_RESP_FUNCTION_COL" }, + {NITF_IF, 0, "& 0x00000400", "EXISTENCE_MASK" }, + {NITF_BCS_N, 7, "Band n Spatial Response Function Uncertainty (Col)", "SPT_RESP_UNC_COL" }, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_BCS_A, 1, "Unit of Spatial Response (Col)", "SPT_RESP_UNIT_COL" }, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "& 0x00000200", "EXISTENCE_MASK" }, + {NITF_BINARY,16, "Field reserved for future use", "DATA_FLD_3" }, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "& 0x00000100", "EXISTENCE_MASK" }, + {NITF_BINARY,24, "Field reserved for future use", "DATA_FLD_4" }, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "& 0x00000080", "EXISTENCE_MASK" }, + {NITF_BINARY,32, "Field reserved for future use", "DATA_FLD_5" }, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "& 0x00000040", "EXISTENCE_MASK" }, + {NITF_BINARY,48, "Field reserved for future use", "DATA_FLD_6" }, + {NITF_ENDIF, 0, NULL, NULL}, + + {NITF_ENDLOOP, 0, NULL, NULL }, + + {NITF_IF, 0, "& 0x00000001", "EXISTENCE_MASK" }, + {NITF_BCS_N, 2, "Number of Auxiliary Band Level Parameters (m)", "NUM_AUX_B" }, + {NITF_BCS_N, 2, "Number of Auxiliary Cube Level Parameters (k)", "NUM_AUX_C" }, + + {NITF_LOOP, 0, NULL, "NUM_AUX_B" }, + + {NITF_BCS_A, 1, "Band Auxiliary Parameter Value Format", "BAPF" }, + {NITF_BCS_A, 7, "Unit of Band Auxiliary Parameter", "UBAP" }, + + {NITF_LOOP, 0, NULL, "COUNT" }, + + {NITF_IF, 0, "eq I", "BAPF" }, + {NITF_BCS_N, 10, "Auxiliary Parameter Integer Value", "APN" }, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq R", "BAPF" }, + {NITF_BINARY, 4, "Auxiliary Parameter Real Value", "APR" }, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq A", "BAPF" }, + {NITF_BCS_N, 20, "Auxiliary Parameter ASCII Value", "APA" }, + {NITF_ENDIF, 0, NULL, NULL}, + + {NITF_ENDLOOP, 0, NULL, NULL }, + {NITF_ENDLOOP, 0, NULL, NULL }, + + {NITF_LOOP, 0, NULL, "NUM_AUX_C" }, + + {NITF_BCS_A, 1, "Cube Auxiliary Parameter Value Format", "CAPF" }, + {NITF_BCS_A, 7, "Unit of Cube Auxiliary Parameter", "UCAP" }, + {NITF_IF, 0, "eq I", "CAPF" }, + {NITF_BCS_N, 10, "Auxiliary Parameter Integer Value", "APN" }, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq R", "CAPF" }, + {NITF_BINARY, 4, "Auxiliary Parameter Real Value", "APR" }, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq A", "CAPF" }, + {NITF_BCS_N, 20, "Auxiliary Parameter ASCII Value", "APA" }, + {NITF_ENDIF, 0, NULL, NULL}, + + {NITF_ENDLOOP, 0, NULL, NULL }, + {NITF_ENDLOOP, 0, NULL, NULL }, + + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(BANDSB, description) + +NITF_CXX_ENDGUARD + + diff --git a/modules/c/nitf/shared/BCKGDA.c b/modules/c/nitf/shared/BCKGDA.c new file mode 100644 index 000000000..a3fb77035 --- /dev/null +++ b/modules/c/nitf/shared/BCKGDA.c @@ -0,0 +1,40 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_N, 8, "Background Width", "BGWIDTH" }, + {NITF_BCS_N, 8, "Background Height", "BGHEIGHT" }, + {NITF_BCS_N, 8, "Background Red", "BGRED" }, + {NITF_BCS_N, 8, "Background Green", "BGGREEN" }, + {NITF_BCS_N, 8, "Background Blue", "BGBLUE" }, + {NITF_BCS_N, 8, "Pixel Size", "PIXSIZE" }, + {NITF_BCS_N, 8, "Pixel Units", "PIXUNITS" }, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(BCKGDA, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/BLOCKA.c b/modules/c/nitf/shared/BLOCKA.c new file mode 100644 index 000000000..23acfaeb3 --- /dev/null +++ b/modules/c/nitf/shared/BLOCKA.c @@ -0,0 +1,45 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_N, 2, "Block Number", "BLOCK_INSTANCE" }, + {NITF_BCS_A, 5, "No. of Gray Pixels", "N_GRAY" }, + {NITF_BCS_N, 5, "Lines", "L_LINES" }, + {NITF_BCS_A, 3, "Layover Angle", "LAYOVER_ANGLE" }, + {NITF_BCS_A, 3, "Shadow Angle", "SHADOW_ANGLE" }, + {NITF_BCS_A, 16, "reserved 1", "RESERVED-001" }, + {NITF_BCS_A, 21, "FRLC Location", "FRLC_LOC" }, + {NITF_BCS_A, 21, "LRLC Location", "LRLC_LOC" }, + {NITF_BCS_A, 21, "LRFC Location", "LRFC_LOC" }, + {NITF_BCS_A, 21, "FRFC Location", "FRFC_LOC" }, + {NITF_BCS_A, 5, "reserved 2", "RESERVED-002" }, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(BLOCKA, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/BNDPLB.c b/modules/c/nitf/shared/BNDPLB.c new file mode 100644 index 000000000..cd83d16a5 --- /dev/null +++ b/modules/c/nitf/shared/BNDPLB.c @@ -0,0 +1,38 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_N, 4, "Number of Points in Bounding Polygon", "NUMPTS" }, + {NITF_LOOP, 0, NULL, "NUMPTS"}, + {NITF_BCS_N, 15, "Longitude/Easting", "LON" }, + {NITF_BCS_N, 15, "Latitude/Northing", "LAT" }, + {NITF_ENDLOOP, 0, NULL, NULL}, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(BNDPLB, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/CLCTNA.c b/modules/c/nitf/shared/CLCTNA.c new file mode 100644 index 000000000..a92a6905c --- /dev/null +++ b/modules/c/nitf/shared/CLCTNA.c @@ -0,0 +1,62 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_N, 4, "VERNUM", "VERNUM" }, + {NITF_BCS_A, 25, "CLCTN_NAME", "CLCTN_NAME" }, + {NITF_BCS_A, 255, "CLCTN_DESCRIPT", "CLCTN_DESCRIPT" }, + {NITF_BCS_A, 8, "CLCTN_STDATE", "CLCTN_STDATE" }, + {NITF_BCS_A, 8, "CLCTN_SPDATE", "CLCTN_SPDATE" }, + {NITF_BCS_A, 11, "CLCTN_LOC", "CLCTN_LOC" }, + {NITF_BCS_A, 2, "COUNTRY", "COUNTRY" }, + {NITF_BCS_A, 20, "SPONSOR", "SPONSOR" }, + {NITF_BCS_A, 100, "PERSONNEL", "PERSONNEL" }, + {NITF_BCS_A, 20, "SCLCTN_NAME", "SCLCTN_NAME" }, + {NITF_BCS_A, 255, "SDESCRIPTION", "SDESCRIPTION" }, + {NITF_BCS_A, 3, "SCLCTN_Z_OFF", "SCLCTN_Z_OFF" }, + {NITF_BCS_A, 8, "SCLCTN_STDATE", "SCLCTN_STDATE" }, + {NITF_BCS_A, 8, "SCLCTN_SPDATE", "SCLCTN_SPDATE" }, + {NITF_BCS_A, 7, "SECURITY", "SECURITY" }, + {NITF_BCS_A, 15, "SCG", "SCG" }, + {NITF_BCS_A, 15, "SITE", "SITE" }, + {NITF_BCS_A, 3, "SITE_NUM", "SITE_NUM" }, + {NITF_BCS_A, 3, "SCN_NUM", "SCN_NUM" }, + {NITF_BCS_A, 2, "FLIGHT_NUM", "FLIGHT_NUM" }, + {NITF_BCS_A, 2, "PASS_NUM", "PASS_NUM" }, + {NITF_BCS_A, 11, "SCN_CNTR", "SCN_CNTR" }, + {NITF_BCS_A, 5, "ALTITUDE", "ALTITUDE" }, + {NITF_BCS_A, 50, "SCN_CONTENT", "SCN_CONTENT" }, + {NITF_BCS_A, 50, "BGRND_TYPE", "BGRND_TYPE" }, + {NITF_BCS_A, 20, "WX_STATION", "WX_STATION" }, + {NITF_BCS_A, 15, "WX_OVERVIEW", "WX_OVERVIEW" }, + {NITF_BCS_A, 30, "WX_FILE", "WX_FILE" }, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(CLCTNA, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/CLCTNB.c b/modules/c/nitf/shared/CLCTNB.c new file mode 100644 index 000000000..258c4f977 --- /dev/null +++ b/modules/c/nitf/shared/CLCTNB.c @@ -0,0 +1,66 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_N, 4, "VERNUM", "VERNUM" }, + {NITF_BCS_A, 25, "CLCTN_NAME", "CLCTN_NAME" }, + {NITF_BCS_A, 255, "CLCTN_DESCRIPT", "CLCTN_DESCRIPT" }, + {NITF_BCS_A, 8, "CLCTN_STDATE", "CLCTN_STDATE" }, + {NITF_BCS_A, 8, "CLCTN_SPDATE", "CLCTN_SPDATE" }, + {NITF_BCS_A, 11, "CLCTN_LOC", "CLCTN_LOC" }, + {NITF_BCS_A, 15, "SITE", "SITE" }, + {NITF_BCS_A, 2, "COUNTRY", "COUNTRY" }, + {NITF_BCS_A, 20, "SPONSOR", "SPONSOR" }, + {NITF_BCS_A, 100, "PERSONNEL", "PERSONNEL" }, + {NITF_BCS_N, 1, "NUM_SITES", "NUM_SITES" }, + {NITF_LOOP, 0, NULL, "NUM_SITES"}, + {NITF_BCS_A, 20, "SCLCTN_NAME", "SCLCTN_NAME" }, + {NITF_BCS_A, 255, "SDESCRIPTION", "SDESCRIPTION" }, + {NITF_BCS_A, 3, "SITE_NUM", "SITE_NUM" }, + {NITF_BCS_A, 3, "SCN_NUM", "SCN_NUM" }, + {NITF_BCS_A, 8, "SCLCTN_STDATE", "SCLCTN_STDATE" }, + {NITF_BCS_A, 8, "SCLCTN_SPDATE", "SCLCTN_SPDATE" }, + {NITF_BCS_A, 11, "SCN_CNTR", "SCN_CNTR" }, + {NITF_BCS_A, 5, "ALTITUDE", "ALTITUDE" }, + {NITF_BCS_A, 50, "SCN_CONTENT", "SCN_CONTENT" }, + {NITF_BCS_A, 50, "BGRND_TYPE", "BGRND_TYPE" }, + {NITF_BCS_A, 1, "SITE_COV", "SITE_COV" }, + {NITF_ENDLOOP, 0, NULL, NULL}, + {NITF_BCS_A, 3, "SCLCTN_Z_OFF", "SCLCTN_Z_OFF" }, + {NITF_BCS_A, 7, "SECURITY", "SECURITY" }, + {NITF_BCS_A, 15, "SCG", "SCG" }, + {NITF_BCS_A, 2, "FLIGHT_NUM", "FLIGHT_NUM" }, + {NITF_BCS_A, 2, "PASS_NUM", "PASS_NUM" }, + {NITF_BCS_A, 20, "WX_STATION", "WX_STATION" }, + {NITF_BCS_A, 15, "WX_OVERVIEW", "WX_OVERVIEW" }, + {NITF_BCS_A, 30, "WX_FILE", "WX_FILE" }, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(CLCTNB, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/CMETAA.c b/modules/c/nitf/shared/CMETAA.c new file mode 100644 index 000000000..73fae7a65 --- /dev/null +++ b/modules/c/nitf/shared/CMETAA.c @@ -0,0 +1,243 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_N, 2, "Number of Related TREs", "RELATED_TRES" }, + {NITF_BCS_A, 120, "Related TREs", "ADDITIONAL_TRES" }, + {NITF_BCS_A, 12, "Processor Version No.", "RD_PRC_NO" }, + {NITF_BCS_A, 4, "VPH Processing Method", "IF_PROCESS" }, + {NITF_BCS_A, 4, "Nominal Center Freq Band", "RD_CEN_FREQ" }, + {NITF_BCS_A, 5, "Collection Mode", "RD_MODE" }, + {NITF_BCS_N, 4, "Data Patch Number Field", "RD_PATCH_NO" }, + {NITF_BCS_A, 5, "Complex Domain", "CMPLX_DOMAIN" }, + {NITF_BCS_A, 4, "Magnitude Remap", "CMPLX_MAG_REMAP_TYPE" }, + {NITF_BCS_N, 7, "Linear Scale Factor", "CMPLX_LIN_SCALE" }, + {NITF_BCS_N, 7, "Complex Average Power", "CMPLX_AVG_POWER" }, + {NITF_BCS_N, 5, "Complex LinLog Transition Point", "CMPLX_LINLOG_TP" }, + {NITF_BCS_A, 3, "Phase Quantization Flag", "CMPLX_PHASE_QUANT_FLAG" }, + {NITF_BCS_N, 2, "Phase Quantization Bit Depth", + "CMPLX_PHASE_QUANT_BIT_DEPTH" }, + + {NITF_BCS_N, 2, "Size of First Pix Component in Bits", "CMPLX_SIZE_1" }, + {NITF_BCS_N, 2, "Data Compression of First Pixel Component", "CMPLX_IC_1" }, + + {NITF_BCS_N, 2, "Size of Second Pixel Component in Bits", "CMPLX_SIZE_2" }, + {NITF_BCS_N, 2, "Data Compression of Second Pixel Component", "CMPLX_IC_2" }, + + {NITF_BCS_N, 5, "Complex Imagery Compressed Bits per Pixel", "CMPLX_IC_BPP" }, + {NITF_BCS_A, 3, "Type of Weighting", "CMPLX_WEIGHT" }, + {NITF_BCS_N, 2, "Azimuth Sidelobe Level", "CMPLX_AZ_SLL" }, + {NITF_BCS_N, 2, "Range Sidelobe Level", "CMPLX_RNG_SLL" }, + {NITF_BCS_N, 2, "Azimuth Taylor nbar", "CMPLX_AZ_TAY_NBAR" }, + {NITF_BCS_N, 2, "Range Taylor nbar", "CMPLX_RNG_TAY_NBAR" }, + {NITF_BCS_A, 3, "Weighting Normalization", "CMPLX_WEIGHT_NORM" }, + {NITF_BCS_A, 1, "Complex Signal PLane", "CMPLX_SIGNAL_PLANE" }, + {NITF_BCS_N, 6, "Sample Location of DC in row dimension", "IF_DC_SF_ROW" }, + {NITF_BCS_N, 6, "Sample Location of DC in column dimension", "IF_DC_SF_COL" }, + {NITF_BCS_N, 6, "UL Signal Corner, Row", "IF_PATCH_1_ROW" }, + {NITF_BCS_N, 6, "UL Signal Corner, Col", "IF_PATCH_1_COL" }, + {NITF_BCS_N, 6, "UR Signal Corner, Row", "IF_PATCH_2_ROW" }, + {NITF_BCS_N, 6, "UR Signal Corner, Col", "IF_PATCH_2_COL" }, + {NITF_BCS_N, 6, "BR Signal Corner, Row", "IF_PATCH_3_ROW" }, + {NITF_BCS_N, 6, "BR Signal Corner, Col", "IF_PATCH_3_COL" }, + {NITF_BCS_N, 6, "BL Signal Corner, Row", "IF_PATCH_4_ROW" }, + {NITF_BCS_N, 6, "BL Signal Corner, Col", "IF_PATCH_4_COL" }, + {NITF_BCS_N, 8, "IS DC Location Row", "IF_DC_IS_ROW" }, + {NITF_BCS_N, 8, "IS DC Location Column", "IF_DC_IS_COL" }, + {NITF_BCS_N, 8, "Row Location of Patch", "IF_IMG_ROW_DC" }, + {NITF_BCS_N, 8, "Column Location of Patch", "IF_IMG_COL_DC" }, + + {NITF_BCS_N, 6, "UL Tile Corner, Row", "IF_TILE_1_ROW" }, + {NITF_BCS_N, 6, "UL Tile Corner, Column", "IF_TILE_1_COL" }, + {NITF_BCS_N, 6, "UR Tile Corner, Row", "IF_TILE_2_ROW" }, + {NITF_BCS_N, 6, "UR Tile Corner, Column", "IF_TILE_2_COL" }, + {NITF_BCS_N, 6, "LR Tile Corner, Row", "IF_TILE_3_ROW" }, + {NITF_BCS_N, 6, "LR Tile Corner, Column", "IF_TILE_3_COL" }, + {NITF_BCS_N, 6, "LL Tile Corner, Row", "IF_TILE_4_ROW" }, + {NITF_BCS_N, 6, "LL Tile Corner, Column", "IF_TILE_4_COL" }, + {NITF_BCS_A, 1, "Range Deskew Flag", "IF_RD" }, + {NITF_BCS_A, 1, "Range Walk Correction", "IF_RGWLK" }, + {NITF_BCS_A, 1, "Range Keystone/Curv. Cor", "IF_KEYSTN" }, + {NITF_BCS_A, 1, "Residual Linear Shift Co", "IF_LINSFT" }, + {NITF_BCS_A, 1, "Sub-patch Phase Correctn.", "IF_SUBPATCH" }, + {NITF_BCS_A, 1, "Other Geom. Dist. Crtns.", "IF_GEODIST" }, + {NITF_BCS_A, 1, "Range Fall-off Correction", "IF_RGFO" }, + {NITF_BCS_A, 1, "Antenna Beam Pattern Comp", "IF_BEAM_COMP" }, + {NITF_BCS_N, 8, "Range Direction Resolution", "IF_RGRES" }, + {NITF_BCS_N, 8, "Azimuth Resolution", "IF_AZRES" }, + {NITF_BCS_N, 8, "Range Sample Spacing", "IF_RSS" }, + {NITF_BCS_N, 8, "Azimuth Sample Spacing", "IF_AZSS" }, + {NITF_BCS_N, 8, "Range Sample Rate", "IF_RSR" }, + {NITF_BCS_N, 8, "Azimuth Sample Rate", "IF_AZSR" }, + {NITF_BCS_N, 7, "Original Range Samples", "IF_RFFT_SAMP" }, + {NITF_BCS_N, 7, "Original Azimuth Samples", "IF_AZFFT_SAMP" }, + {NITF_BCS_N, 7, "Total Range Samples", "IF_RFFT_TOT" }, + {NITF_BCS_N, 7, "Total Azimuth Samples", "IF_AZFFT_TOT" }, + {NITF_BCS_N, 6, "Sub-patch Size, Row", "IF_SUBP_ROW" }, + {NITF_BCS_N, 6, "Sub-patch Size, Column", "IF_SUBP_COL" }, + {NITF_BCS_N, 4, "Subpatch Counts, Range", "IF_SUB_RG" }, + {NITF_BCS_N, 4, "Subpatch Counts, Azimuth", "IF_SUB_AZ" }, + {NITF_BCS_A, 1, "FFT Sign Convention in Range", "IF_RFFTS" }, + {NITF_BCS_A, 1, "FFT Sign Convention in Azimuth", "IF_AFFTS" }, + {NITF_BCS_A, 7, "Range Data Range", "IF_RANGE_DATA" }, + {NITF_BCS_A, 1, "Increasing phase", "IF_INCPH" }, + {NITF_BCS_A, 8, "Super Res. Alg. Name (1st Iter)", "IF_SR_NAME1" }, + + {NITF_BCS_N, 8, "Amount/Factor of Super Res. Applied (1st Iter)", "IF_SR_AMOUNT1" }, + {NITF_BCS_A, 8, "Super Res. Alg. Name (2nd Iter)", "IF_SR_NAME2" }, + {NITF_BCS_N, 8, "Amount/Factor of Super Res. Applied (2nd Iter)", + "IF_SR_AMOUNT2" }, + {NITF_BCS_A, 8, "Super Res. Alg. Name (3rd Iter)", "IF_SR_NAME3" }, + {NITF_BCS_N, 8, "Amount/Factor of Super Res. Applied (3rd Iter)", "IF_SR_AMOUNT" }, + {NITF_BCS_A, 5, "First Autofocus Iteration", "AF_TYPE1" }, + {NITF_BCS_A, 5, "Second Autofocus Iteration", "AF_TYPE2" }, + {NITF_BCS_A, 5, "Third Autofocus Iteration", "AF_TYPE3" }, + {NITF_BCS_A, 1, "Transmit Polarization", "POL_TR" }, + {NITF_BCS_A, 1, "Receive Polarization", "POL_RE" }, + {NITF_BCS_A, 40, "Polarization Frame of Ref.", "POL_REFERENCE" }, + {NITF_BCS_A, 1, "Polarimetric Data Set", "POL" }, + {NITF_BCS_A, 1, "Pixel Registered", "POL_REG" }, + + {NITF_BCS_N, 5, "Minimum Polarization Isolation", "POL_ISO_1" }, + {NITF_BCS_A, 1, "RCS Gray Level Balancing", "POL_BAL" }, + {NITF_BCS_N, 8, "Pixel Amplitude Balance Coeff", "POL_BAL_MAG" }, + {NITF_BCS_N, 8, "Pixel Phase Balance Coeff", "POL_BAL_PHS" }, + {NITF_BCS_A, 1, "Radar Hardware Phase Bal.", "POL_HCOMP" }, + {NITF_BCS_A, 10, "Basis Set", "POL_HCOMP_BASIS" }, + {NITF_BCS_N, 9, "First Radar HW Phase Bal.", "POL_HCOMP_COEF_1" }, + {NITF_BCS_N, 9, "Second Radar HW Phase Bal", "POL_HCOMP_COEF_2" }, + {NITF_BCS_N, 9, "Third Radar HW Phase Bal.", "POL_HCOMP_COEF_3" }, + {NITF_BCS_N, 1, "Radar Autofocus Phase Bal.", "POL_AFCOMP" }, + {NITF_BCS_A, 15, "Spare alpha field", "POL_SPARE_A" }, + {NITF_BCS_N, 9, "Spare numeric field", "POL_SPARE_N" }, + {NITF_BCS_A, 9, "Collection Date", "T_UTC_YYYYMMMDD" }, + {NITF_BCS_N, 6, "Collection Time", "T_HHMMSSUTC" }, + {NITF_BCS_A, 6, "Civil Time of Collection", "T_HHMMSSLOCAL" }, + {NITF_BCS_N, 11, "Slant Range at Sensor Reference Center", "CG_SRAC" }, + {NITF_BCS_N, 7, "Slant Range 95% Confidence Interval", "CG_SLANT_CONFIDENCE" }, + {NITF_BCS_N, 11, "Cross Track Range at Sensor Reference Center", "CG_CROSS" }, + {NITF_BCS_N, 7, "Cross Track Range 95% Confidence Interval", "CG_CROSS_CONFIDENCE" }, + {NITF_BCS_N, 9, "Cone Angle at Sensor Reference Point", "CG_CAAC" }, + {NITF_BCS_N, 6, "Cone Angle 95% Confidence", "CG_CONE_CONFIDENCE" }, + {NITF_BCS_N, 8, "Ground Plane Squint Angle", "CG_GPSAC" }, + {NITF_BCS_N, 6, "Squint Angle 95% Confidence", "CG_GPSAC_CONFIDENCE" }, + {NITF_BCS_N, 8, "Slant Plane Squint Angle", "CG_SQUINT" }, + {NITF_BCS_N, 7, "Grazing Angle at Sensor Reference Point Center", "CG_GAAC" }, + {NITF_BCS_N, 6, "Grazing Angle at Sensor Reference Point Center 95% Confidence", "CG_GAAC_CONFIDENCE" }, + {NITF_BCS_N, 7, "Incidence angle", "CG_INCIDENT" }, + {NITF_BCS_N, 7, "Slope angle", "CG_SLOPE" }, + {NITF_BCS_N, 8, "Tilt angle", "CG_TILT" }, + {NITF_BCS_A, 1, "Look Direction", "CG_LD" }, + {NITF_BCS_N, 8, "North Relative to Top Image Edge", "CG_NORTH" }, + {NITF_BCS_N, 6, "North Angle 95% Confidence", "CG_NORTH_CONFIDENCE" }, + {NITF_BCS_N, 8, "East Relative to Top Image Edge", "CG_EAST" }, + {NITF_BCS_N, 8, "Range LOS Relative to Top Image Edge", "CG_RLOS" }, + {NITF_BCS_N, 6, "Range LOS 95% Confidence", "CG_LOS_CONFIDENCE" }, + {NITF_BCS_N, 8, "Layover Angle", "CG_LAYOVER" }, + {NITF_BCS_N, 8, "Shadow Angle", "CG_SHADOW" }, + {NITF_BCS_N, 7, "Out of Plane Motion", "CG_OPM" }, + {NITF_BCS_A, 5, "Nominal Geometry Reference", "CG_MODEL" }, + {NITF_BCS_N, 13, "Aimpoint of Antenna, x", "CG_AMPT_X" }, + {NITF_BCS_N, 13, "Aimpoint of Antenna, y", "CG_AMPT_Y" }, + {NITF_BCS_N, 13, "Aimpoint of Antenna, z", "CG_AMPT_Z" }, + {NITF_BCS_N, 6, "Aimpoint X,Y 95% Confidence", "CG_AP_CONF_XY" }, + {NITF_BCS_N, 6, "Aimpoint Z 95% Confidence", "CG_AP_CONF_Z" }, + {NITF_BCS_N, 13, "Sensor Reference Point, x", "CG_APCEN_X" }, + {NITF_BCS_N, 13, "Sensor Reference Point, y", "CG_APCEN_Y" }, + {NITF_BCS_N, 13, "Sensor Reference Point, z", "CG_APCEN_Z" }, + {NITF_BCS_N, 6, "SRP X,Y 95% Confidence", "CG_APER_CONF_XY" }, + {NITF_BCS_N, 6, "SRP Z 95% Confidence", "CG_APER_CONF_Z" }, + {NITF_BCS_N, 9, "Focus Plane Normal UV, x", "CG_FPNUV_X" }, + {NITF_BCS_N, 9, "Focus Plane Normal UV, y", "CG_FPNUV_Y" }, + {NITF_BCS_N, 9, "Focus Plane Normal UV, z", "CG_FPNUV_Z" }, + {NITF_BCS_N, 9, "Image Display Plane NUV, x", "CG_IDPNUVX" }, + {NITF_BCS_N, 9, "Image Display Plane NUV, y", "CG_IDPNUVY" }, + {NITF_BCS_N, 9, "Image Display Plane NUV, z", "CG_IDPNUVZ" }, + {NITF_BCS_N, 13, "Scene Center, x", "CG_SCECN_X" }, + {NITF_BCS_N, 13, "Scene Center, y", "CG_SCECN_Y" }, + {NITF_BCS_N, 13, "Scene Center, z", "CG_SCECN_Z" }, + {NITF_BCS_N, 6, "Scene Center X,Y 95% Conf", "CG_SC_CONF_XY" }, + {NITF_BCS_N, 6, "Scene Center Z 95% Confid", "CG_SC_CONF_Z" }, + {NITF_BCS_N, 8, "Swath Width", "CG_SWWD" }, + {NITF_BCS_N, 10, "Sensor Nominal Velocity, x", "CG_SNVEL_X" }, + {NITF_BCS_N, 10, "Sensor Nominal Velocity, y", "CG_SNVEL_Y" }, + {NITF_BCS_N, 10, "Sensor Nominal Velocity, z", "CG_SNVEL_Z" }, + {NITF_BCS_N, 10, "Sensor Nominal Accel, x", "CG_SNACC_X" }, + {NITF_BCS_N, 10, "Sensor Nominal Accel, y", "CG_SNACC_Y" }, + {NITF_BCS_N, 10, "Sensor Nominal Accel, z", "CG_SNACC_Z" }, + {NITF_BCS_N, 8, "Sensor Nom. Attitude Roll", "CG_SNATT_ROLL" }, + {NITF_BCS_N, 8, "Sensor Nom. Attitude Pitch", "CG_SNATT_PITCH" }, + {NITF_BCS_N, 8, "Sensor Nom. Attitude Yaw", "CG_SNATT_YAW" }, + {NITF_BCS_N, 9, "Geoid Tangent Plane Normal, x", "CG_GTP_X" }, + {NITF_BCS_N, 9, "Geoid Tangent Plane Normal, y", "CG_GTP_Y" }, + {NITF_BCS_N, 9, "Geoid Tangent Plane Normal, z", "CG_GTP_Z" }, + {NITF_BCS_A, 4, "Mapping Coordinate", "CG_MAP_TYPE" }, + {NITF_IF, 0, "eq GEOD", "CG_MAP_TYPE"}, + {NITF_BCS_N, 11, "Lat of the Patch Center", "CG_PATCH_LATCEN" }, + {NITF_BCS_N, 12, "Long of the Patch Center", "CG_PATCH_LNGCEN" }, + {NITF_BCS_N, 11, "Lat of Patch Corner, upper left", "CG_PATCH_LTCORUL" }, + {NITF_BCS_N, 12, "Lon of Patch Corner, upper left", "CG_PATCH_LGCORUL" }, + {NITF_BCS_N, 11, "Lat of Patch Corner, upper right", "CG_PATCH_LTCORUR" }, + {NITF_BCS_N, 12, "Lon of Patch Corner, upper right", "CG_PATCH_LGCORUR" }, + {NITF_BCS_N, 11, "Lat of Patch Corner, lower right", "CG_PATCH_LTCORLR" }, + {NITF_BCS_N, 12, "Lon of Patch Corner, lower right", "CG_PATCH_LGCORLR" }, + {NITF_BCS_N, 11, "Lat of Patch Corner, lower left", "CG_PATCH_LTCORLL" }, + {NITF_BCS_N, 12, "Lon of Patch Corner, lower left", "CG_PATCH_LNGCOLL" }, + {NITF_BCS_N, 9, "Latitude 95% Confidence", "CG_PATCH_LAT_CONFIDENCE" }, + {NITF_BCS_N, 9, "Longitude 95% Confidence", "CG_PATCH_LONG_CONFIDENCE" }, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq MGRS", "CG_MAP_TYPE"}, + {NITF_BCS_A, 23, "MGRS Image Center", "CG_MGRS_CENT" }, + {NITF_BCS_A, 23, "MGRS Image Upper Left Corn", "CG_MGRSCORUL" }, + {NITF_BCS_A, 23, "MGRS Image Upper RightCorn", "CG_MGRSCORUR" }, + {NITF_BCS_A, 23, "MGRS Image Lower RightCorn", "CG_MGRSCORLR" }, + {NITF_BCS_A, 23, "MGRS Image Lower Left Corn", "CG_MGRCORLL" }, + {NITF_BCS_N, 7, "MGRS 95% Confidence", "CG_MGRS_CONFIDENCE" }, + {NITF_BCS_A, 11, "MGRS Blank Padding", "CG_MGRS_PAD" }, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq NA", "CG_MAP_TYPE"}, + {NITF_BCS_A, 133, "Map Coordinate Padding", "CG_MAP_TYPE_BLANK" }, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_BCS_A, 144, "Spare Alpha field", "CG_SPARE_A" }, + {NITF_BCS_N, 7, "Radiometric Calibration Parameter", "CA_CALPA" }, + {NITF_BCS_N, 14, "Chirp Start Frequency", "WF_SRTFR" }, + {NITF_BCS_N, 14, "Chirp End Frequency", "WF_ENDFR" }, + {NITF_BCS_N, 10, "Chirp Rate", "WF_CHRPRT" }, + {NITF_BCS_N, 9, "Pulsewidth", "WF_WIDTH" }, + {NITF_BCS_N, 13, "Center frequency", "WF_CENFRQ" }, + {NITF_BCS_N, 13, "Chirp Bandwidth", "WF_BW" }, + {NITF_BCS_N, 7, "Pulse Repetition Frequency", "WF_PRF" }, + {NITF_BCS_N, 9, "Pulse Repetition Interval", "WF_PRI" }, + {NITF_BCS_N, 7, "Coherent Data Period", "WF_CDP" }, + {NITF_BCS_N, 9, "Number of Pulses", "WF_NUMBER_OF_PULSES" }, + {NITF_BCS_A, 1, "VPH Data", "VPH_COND" }, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(CMETAA, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/CSCCGA.c b/modules/c/nitf/shared/CSCCGA.c new file mode 100644 index 000000000..91a1f4950 --- /dev/null +++ b/modules/c/nitf/shared/CSCCGA.c @@ -0,0 +1,42 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_A, 18, "Source of Grid", "CCG_SOURCE" }, + {NITF_BCS_A, 6, "Image Segment Sensor to which CCG is registered", "REG_SENSOR" }, + {NITF_BCS_N, 7, "CCG Origin - Line", "ORIGIN_LINE" }, + {NITF_BCS_N, 5, "CCG Origin - Sample", "ORIGIN_SAMPLE" }, + {NITF_BCS_N, 7, "Along Scan Cell Size - Lines", "AS_CELL_SIZE" }, + {NITF_BCS_N, 5, "Cross Scan Cell Size - Samples", "CS_CELL_SIZE" }, + {NITF_BCS_N, 7, "Number of Rows in CCG", "CCG_MAX_LINE" }, + {NITF_BCS_N, 5, "Number of Columns in CCG", "CCG_MAX_SAMPLE" }, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(CSCCGA, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/CSCRNA.c b/modules/c/nitf/shared/CSCRNA.c new file mode 100644 index 000000000..257b97a06 --- /dev/null +++ b/modules/c/nitf/shared/CSCRNA.c @@ -0,0 +1,47 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_A, 1, "predicted corners flag", "PREDICT_CORNERS" }, + {NITF_BCS_N, 9, "lat UL", "ULCNR_LAT" }, + {NITF_BCS_N, 10, "long UL", "ULCNR_LONG" }, + {NITF_BCS_N, 8, "height UL", "ULCNR_HT" }, + {NITF_BCS_N, 9, "lat UR", "URCNR_LAT" }, + {NITF_BCS_N, 10, "long UR", "URCNR_LONG" }, + {NITF_BCS_N, 8, "height UR", "URCNR_HT" }, + {NITF_BCS_N, 9, "lat LR", "LRCNR_LAT" }, + {NITF_BCS_N, 10, "long LR", "LRCNR_LONG" }, + {NITF_BCS_N, 8, "height LR", "LRCNR_HT" }, + {NITF_BCS_N, 9, "lat LL", "LLCNR_LAT" }, + {NITF_BCS_N, 10, "long LL", "LLCNR_LONG" }, + {NITF_BCS_N, 8, "height LL", "LLCNR_HT" }, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(CSCRNA, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/CSDIDA.c b/modules/c/nitf/shared/CSDIDA.c new file mode 100644 index 000000000..fe860d6ae --- /dev/null +++ b/modules/c/nitf/shared/CSDIDA.c @@ -0,0 +1,29 @@ + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_N, 2, "Day of Dataset Collection", "DAY" }, + {NITF_BCS_A, 3, "Month of Dataset Collection", "MONTH" }, + {NITF_BCS_N, 4, "Year of Dataset Collection", "YEAR" }, + {NITF_BCS_A, 2, "Platform Identification", "PLATFORM_CODE" }, + {NITF_BCS_N, 2, "Vehicle Number", "VEHICLE_ID" }, + {NITF_BCS_N, 2, "Pass Number", "PASS" }, + {NITF_BCS_N, 3, "Operation Number", "OPERATION" }, + {NITF_BCS_A, 2, "Sensor ID", "SENSOR_ID" }, + {NITF_BCS_A, 2, "Product ID", "PRODUCT_ID" }, + {NITF_BCS_A, 4, "Reserved", "RESERVED_1" }, + {NITF_BCS_N, 14, "Image Start Time", "TIME" }, + {NITF_BCS_N, 14, "Process Completion Time", "PROCESS_TIME" }, + {NITF_BCS_N, 2, "Reserved", "RESERVED_2" }, + {NITF_BCS_N, 2, "Reserved", "RESERVED_3" }, + {NITF_BCS_A, 1, "Reserved", "RESERVED_4" }, + {NITF_BCS_A, 1, "Reserved", "RESERVED_5" }, + {NITF_BCS_A, 10, "Software Version Used", "SOFTWARE_VERSION_NUMBER" }, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(CSDIDA, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/CSEPHA.c b/modules/c/nitf/shared/CSEPHA.c new file mode 100644 index 000000000..e562e55f3 --- /dev/null +++ b/modules/c/nitf/shared/CSEPHA.c @@ -0,0 +1,44 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_A, 12, "ephemeris flag", "EPHEM_FLAG" }, + {NITF_BCS_N, 5, "time b/w eph vectors", "DT_EPHEM" }, + {NITF_BCS_N, 8, "day of first eph vector", "DATE_EPHEM" }, + {NITF_BCS_N, 13, "UTC of first eph vector", "T0_EPHEM" }, + {NITF_BCS_N, 3, "number of eph vectors", "NUM_EPHEM" }, + {NITF_LOOP, 0, NULL, "NUM_EPHEM"}, + {NITF_BCS_N, 12, "x-coor of eph vector", "EPHEM_X" }, + {NITF_BCS_N, 12, "y-coor of eph vector", "EPHEM_Y" }, + {NITF_BCS_N, 12, "z-coor of eph vector", "EPHEM_Z" }, + {NITF_ENDLOOP, 0, NULL, NULL}, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(CSEPHA, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/CSEXRA.c b/modules/c/nitf/shared/CSEXRA.c new file mode 100644 index 000000000..d5ee406dc --- /dev/null +++ b/modules/c/nitf/shared/CSEXRA.c @@ -0,0 +1,57 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_A, 6, "Sensor", "SENSOR" }, + {NITF_BCS_N, 12, "Time of the First Line of Image", "TIME_FIRST_LINE_IMAGE" }, + {NITF_BCS_N, 12, "Image Duration Time", "TIME_IMAGE_DURATION" }, + {NITF_BCS_N, 5, "Maximum Mean Ground Sample Distance", "MAX_GSD" }, + {NITF_BCS_A, 5, "Along Scan GSD", "ALONG_SCAN_GSD" }, + {NITF_BCS_A, 5, "Cross-Scan GSD", "CROSS_SCAN_GSD" }, + {NITF_BCS_A, 5, "Geometric Mean GSD", "GEO_MEAN_GSD" }, + {NITF_BCS_A, 5, "Along Scan Vertical GSD", "A_S_VERT_GSD" }, + {NITF_BCS_A, 5, "Cross-Scan Vertical GSD", "C_S_VERT_GSD" }, + {NITF_BCS_A, 5, "Geometric Mean Vertical GSD", "GEO_MEAN_VERT_GSD" }, + {NITF_BCS_A, 5, "GSD Beta Angle", "GSD_BETA_ANGLE" }, + {NITF_BCS_N, 5, "Dynamic range of pixels in image", "DYNAMIC_RANGE" }, + {NITF_BCS_N, 7, "Number of Lines", "NUM_LINES" }, + {NITF_BCS_N, 5, "Number of Samples", "NUM_SAMPLES" }, + {NITF_BCS_N, 7, "Nominal Angle to True North", "ANGLE_TO_NORTH" }, + {NITF_BCS_N, 6, "Nominal Obliquity angle", "OBLIQUITY_ANGLE" }, + {NITF_BCS_N, 7, "Azimuth of Obliquity", "AZ_OF_OBLIQUITY" }, + {NITF_BCS_N, 1, "Ground Cover", "GRD_COVER" }, + {NITF_BCS_N, 1, "Snow Depth Category", "SNOW_DEPTH_CAT" }, + {NITF_BCS_N, 7, "Sun Azimuth Angle", "SUN_AZIMUTH" }, + {NITF_BCS_N, 7, "Sun Elevation Angle", "SUN_ELEVATION" }, + {NITF_BCS_A, 3, "Predicted NIIRS", "PREDICTED_NIIRS" }, + {NITF_BCS_N, 3, "Circular Error", "CIRCL_ERR" }, + {NITF_BCS_N, 3, "Linear Error", "LINEAR_ERR" }, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(CSEXRA, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/CSPROA.c b/modules/c/nitf/shared/CSPROA.c new file mode 100644 index 000000000..951e6220b --- /dev/null +++ b/modules/c/nitf/shared/CSPROA.c @@ -0,0 +1,44 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_A, 12, "fill0", "RESERVED_0" }, + {NITF_BCS_A, 12, "fill1", "RESERVED_1" }, + {NITF_BCS_A, 12, "fill2", "RESERVED_2" }, + {NITF_BCS_A, 12, "fill3", "RESERVED_3" }, + {NITF_BCS_A, 12, "fill4", "RESERVED_4" }, + {NITF_BCS_A, 12, "fill5", "RESERVED_5" }, + {NITF_BCS_A, 12, "fill6", "RESERVED_6" }, + {NITF_BCS_A, 12, "fill7", "RESERVED_7" }, + {NITF_BCS_A, 12, "fill8", "RESERVED_8" }, + {NITF_BCS_A, 12, "compression", "BWC" }, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(CSPROA, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/CSSFAA.c b/modules/c/nitf/shared/CSSFAA.c new file mode 100644 index 000000000..af737c7f9 --- /dev/null +++ b/modules/c/nitf/shared/CSSFAA.c @@ -0,0 +1,50 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_N, 1, "number of bands", "NUM_BANDS" }, + {NITF_LOOP, 0, NULL, "NUM_BANDS"}, + {NITF_BCS_A, 1, "band category", "BAND_TYPE" }, + {NITF_BCS_A, 6, "band wavelength center", "BAND_ID" }, + {NITF_BCS_N, 11, "focal length", "FOC_LENGTH" }, + {NITF_BCS_N, 8, "num linear arrays", "NUM_DAP" }, + {NITF_BCS_N, 8, "first sample number", "NUM_FIR" }, + {NITF_BCS_N, 7, "number detector elements", "DELTA" }, + {NITF_BCS_N, 7, "pp offset x", "OPPOFF_X" }, + {NITF_BCS_N, 7, "pp offset y", "OPPOFF_Y" }, + {NITF_BCS_N, 7, "pp offset z", "OPPOFF_Z" }, + {NITF_BCS_N, 11, "dm first pixel x", "START_X" }, + {NITF_BCS_N, 11, "dm first pixel y", "START_Y" }, + {NITF_BCS_N, 11, "dm last pixel x", "FINISH_X" }, + {NITF_BCS_N, 11, "dm last pixel y", "FINISH_Y" }, + {NITF_ENDLOOP, 0, NULL, NULL}, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(CSSFAA, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/CSSHPA.c b/modules/c/nitf/shared/CSSHPA.c new file mode 100644 index 000000000..9a6f4e847 --- /dev/null +++ b/modules/c/nitf/shared/CSSHPA.c @@ -0,0 +1,45 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_A, 25, "Shapefile Use", "SHAPE_USE" }, + {NITF_BCS_A, 10, "Type of shapes", "SHAPE_CLASS" }, + {NITF_IF, 0, "eq CLOUD_SHAPES ", "SHAPE_USE"}, + {NITF_BCS_A, 18, "Source sensors(s) for determining cloud cover", "CC_SOURCE" }, + {NITF_ENDIF, 0, NULL, NULL }, + {NITF_BCS_A, 3, "Name of first file in shapefile", "SHAPE1_NAME" }, + {NITF_BCS_N, 6, "Start location in bytes of the file as offset in the DES USER data", "SHAPE1_START" }, + {NITF_BCS_A, 3, "Name of second file in shapefile", "SHAPE2_NAME" }, + {NITF_BCS_N, 6, "Start location in bytes of the file as offset in the DES USER data", "SHAPE2_START" }, + {NITF_BCS_A, 3, "Name of third file in shapefile", "SHAPE3_NAME" }, + {NITF_BCS_N, 6, "Start location in bytes of the file as offset in the DES USER data", "SHAPE3_START" }, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(CSSHPA, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/ENGRDA.c b/modules/c/nitf/shared/ENGRDA.c new file mode 100644 index 000000000..d76f3fc04 --- /dev/null +++ b/modules/c/nitf/shared/ENGRDA.c @@ -0,0 +1,312 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_A, 20, "Unique Source System Name", "RESRC" }, + {NITF_BCS_N, 3, "Record Entry Count", "RECNT" }, + {NITF_LOOP, 0, NULL, "RECNT"}, + {NITF_BCS_N, 2, "Engineering Data Label Length", "ENGLN" }, + /* This one we don't know the length of, so we have to use the special length tag */ + {NITF_BCS_A, NITF_TRE_CONDITIONAL_LENGTH, "Engineering Data Label", + "ENGLBL", "ENGLN" }, + {NITF_BCS_N, 4, "Engineering Matrix Data Column Count", "ENGMTXC" }, + {NITF_BCS_N, 4, "Engineering Matrix Data Row Count", "ENGMTXR" }, + {NITF_BCS_A, 1, "Value Type of Engineering Data Element", "ENGTYP" }, + {NITF_BCS_N, 1, "Engineering Data Element Size", "ENGDTS" }, + {NITF_BCS_A, 2, "Engineering Data Units", "ENGDATU" }, + {NITF_BCS_N, 8, "Engineering Data Count", "ENGDATC" }, + /* This one we don't know the length of, so we have to use the special length tag */ + /* Notice that we use postfix notation to compute the length + * We also don't know the type of data (it depends on ENGDTS), so + * we need to override the TREHandler's read method. If we don't do + * this, not only will the field type potentially be wrong, but + * strings will be endian swapped if they're of length 2 or 4. */ + {NITF_BINARY, NITF_TRE_CONDITIONAL_LENGTH, "Engineering Data", + "ENGDATA", "ENGDATC ENGDTS *"}, + {NITF_ENDLOOP, 0, NULL, NULL}, + {NITF_END, 0, NULL, NULL} +}; + +static nitf_TREDescriptionInfo descriptions[] = { + { "ENGRDA", description, NITF_TRE_DESC_NO_LENGTH }, + { NULL, NULL, NITF_TRE_DESC_NO_LENGTH } + }; + +static nitf_TREDescriptionSet descriptionSet = { 0, descriptions }; + +static const char *ident[] = { NITF_PLUGIN_TRE_KEY, "ENGRDA", NULL }; + +static nitf_TREHandler engrdaHandler; + +/* TODO This is a cut and paste of nitf_TREUtils_parse() with a little bit + * of extra logic for determining the appropriate field type for + * engineering data. Is there a way to reuse more of the other + * parse function? */ +NITFPRIV(int) ENGRDA_parse(nitf_TRE * tre, + char *bufptr, + nitf_Error * error) +{ + int status = 1; + int iterStatus = NITF_SUCCESS; + int offset = 0; + int length; + nitf_TRECursor cursor; + nitf_Field *field = NULL; + nitf_TREPrivateData *privData = NULL; + nitf_FieldType prevValueType; + nitf_FieldType fieldType; + + /* get out if TRE is null */ + if (!tre) + { + nitf_Error_init(error, "parse -> invalid tre object", + NITF_CTXT, NITF_ERR_INVALID_PARAMETER); + return NITF_FAILURE; + } + + privData = (nitf_TREPrivateData*)tre->priv; + + /* flush the hash first, to protect from duplicate entries */ + if (privData) + { + nitf_TREPrivateData_flush(privData, error); + } + + cursor = nitf_TRECursor_begin(tre); + prevValueType = NITF_BINARY; + while (offset < privData->length && status) + { + if ((iterStatus = + nitf_TRECursor_iterate(&cursor, error)) == NITF_SUCCESS) + { + length = cursor.length; + if (length == NITF_TRE_GOBBLE) + { + length = privData->length - offset; + } + + /* no need to call setValue, because we already know + * it is OK for this one to be in the hash + */ + + /* for engineering data, the TREDescription specifies the type as + * binary but in reality it's based on the value type field. this + * will be saved off for us below. it's also critical to set this + * correctly so that string types don't get endian swapped. */ + fieldType = + !strncmp(cursor.tag_str, "ENGDATA", 7) ? + prevValueType : cursor.desc_ptr->data_type; + + /* construct the field */ + field = nitf_Field_construct(length, fieldType, error); + if (!field) + goto CATCH_ERROR; + + /* first, check to see if we need to swap bytes */ + if (field->type == NITF_BINARY + && (length == NITF_INT16_SZ || length == NITF_INT32_SZ)) + { + if (length == NITF_INT16_SZ) + { + nitf_Int16 int16 = + (nitf_Int16)NITF_NTOHS(*((nitf_Int16 *) (bufptr + offset))); + status = nitf_Field_setRawData(field, + (NITF_DATA *) & int16, length, error); + } + else if (length == NITF_INT32_SZ) + { + nitf_Int32 int32 = + (nitf_Int32)NITF_NTOHL(*((nitf_Int32 *) (bufptr + offset))); + status = nitf_Field_setRawData(field, + (NITF_DATA *) & int32, length, error); + } + } + else + { + /* check for the other binary lengths ... */ + if (field->type == NITF_BINARY) + { + /* TODO what to do??? 8 bit is ok, but what about 64? */ + /* for now, just let it go through... */ + } + + /* now, set the data */ + status = nitf_Field_setRawData(field, (NITF_DATA *) (bufptr + offset), + length, error); + } + + /* when we see the value type, save it off + * we'll eventually read this when we get to the engineering data + * itself */ + if (!strncmp(cursor.tag_str, "ENGTYP", 6) && + field->type == NITF_BCS_A && + field->length == 1) + { + prevValueType = (field->raw[0] == 'A') ? + NITF_BCS_A : NITF_BINARY; + } + +#ifdef NITF_DEBUG + { + fprintf(stdout, "Adding Field [%s] to TRE [%s]\n", + cursor.tag_str, tre->tag); + } +#endif + + /* add to the hash */ + nitf_HashTable_insert(((nitf_TREPrivateData*)tre->priv)->hash, + cursor.tag_str, field, error); + + offset += length; + } + /* otherwise, the iterate function thinks we are done */ + else + { + break; + } + } + nitf_TRECursor_cleanup(&cursor); + + /* check if we still have more to parse, and throw an error if so */ + if (offset < privData->length) + { + nitf_Error_init(error, "TRE data is longer than it should be", + NITF_CTXT, NITF_ERR_INVALID_OBJECT); + status = NITF_FAILURE; + } + return status; + + /* deal with errors here */ + CATCH_ERROR: + return NITF_FAILURE; +} + +/* TODO This is a cut and paste of nitf_TREUtils_basicRead() except that it + * calls ENGRDA_parse() instead. Is there a way to reuse more of the + * original read function? + */ +NITFPRIV(NITF_BOOL) ENGRDA_read(nitf_IOInterface* io, + nitf_Uint32 length, + nitf_TRE* tre, + struct _nitf_Record* record, + nitf_Error* error) +{ + int ok; + char *data = NULL; + nitf_TREDescriptionSet *descriptions = NULL; + nitf_TREDescriptionInfo *infoPtr = NULL; + + if (!tre) + return NITF_FAILURE; + + data = (char*)NITF_MALLOC( length ); + if (!data) + { + nitf_Error_init(error, NITF_STRERROR( NITF_ERRNO ),NITF_CTXT, NITF_ERR_MEMORY ); + return NITF_FAILURE; + } + memset(data, 0, length); + if (!nitf_TREUtils_readField(io, data, length, error)) + { + NITF_FREE(data); + return NITF_FAILURE; + } + + descriptions = (nitf_TREDescriptionSet*)tre->handler->data; + + if (!descriptions) + { + nitf_Error_init(error, "TRE Description Set is NULL", + NITF_CTXT, NITF_ERR_INVALID_OBJECT); + + NITF_FREE(data); + return NITF_FAILURE; + } + + tre->priv = NULL; + infoPtr = descriptions->descriptions; + tre->priv = nitf_TREPrivateData_construct(error); + ((nitf_TREPrivateData*)tre->priv)->length = length; + + ok = NITF_FAILURE; + while (infoPtr && (infoPtr->description != NULL)) + { + if (!tre->priv) + { + break; + } + + ((nitf_TREPrivateData*)tre->priv)->description = infoPtr->description; +#ifdef NITF_DEBUG + printf("Trying TRE with description: %s\n\n", infoPtr->name); +#endif + ok = ENGRDA_parse(tre, data, error); + if (ok) + { + nitf_TREPrivateData *priv = (nitf_TREPrivateData*)tre->priv; + /* copy the name */ + if (!nitf_TREPrivateData_setDescriptionName( + priv, infoPtr->name, error)) + { + /* something bad happened... so we need to cleanup */ + NITF_FREE(data); + nitf_TREPrivateData_destruct(&priv); + tre->priv = NULL; + return NITF_FAILURE; + } + break; + } + + infoPtr++; + } + + if (data) NITF_FREE(data); + return ok; +} + +NITFAPI(const char**) ENGRDA_init(nitf_Error* error) +{ + if (!nitf_TREUtils_createBasicHandler(&descriptionSet, + &engrdaHandler, + error)) + { + return NULL; + } + + /* Override the read function with one that will set the engineering + data's field type based on the TRE's value type */ + engrdaHandler.read = ENGRDA_read; + + return ident; +} + +NITFAPI(nitf_TREHandler*) ENGRDA_handler(nitf_Error* error) +{ + return &engrdaHandler; +} + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/EXOPTA.c b/modules/c/nitf/shared/EXOPTA.c new file mode 100644 index 000000000..f3fa11044 --- /dev/null +++ b/modules/c/nitf/shared/EXOPTA.c @@ -0,0 +1,51 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_A, 3, "ANGLE TO NORTH", "ANGLETONORTH" }, + {NITF_BCS_A, 5, "MEAN GSD", "MEANGSD" }, + {NITF_BCS_A, 1, "Reserved 1", "RESERV01" }, + {NITF_BCS_A, 5, "DYNAMIC RANGE", "DYNAMICRANGE" }, + {NITF_BCS_A, 7, "Reserved 2", "RESERV02" }, + {NITF_BCS_A, 5, "OBL ANG", "OBLANG" }, + {NITF_BCS_A, 6, "ROLL ANG", "ROLLANG" }, + {NITF_BCS_A, 12, "PRIME ID", "PRIMEID" }, + {NITF_BCS_A, 15, "PRIME BE", "PRIMEBE" }, + {NITF_BCS_A, 5, "Reserved 3", "RESERV03" }, + {NITF_BCS_A, 3, "N SEC", "NSEC" }, + {NITF_BCS_A, 2, "Reserved 4", "RESERV04" }, + {NITF_BCS_A, 7, "Reserved 5", "RESERV05" }, + {NITF_BCS_A, 3, "N SEG", "NSEG" }, + {NITF_BCS_A, 6, "MAX LP SEG", "MAXLPSEG" }, + {NITF_BCS_A, 12, "Reserved 6", "RESERV06" }, + {NITF_BCS_A, 5, "SUN EL", "SUNEL" }, + {NITF_BCS_A, 5, "SUN AZ", "SUNAZ" }, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(EXOPTA, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/EXPLTA.c b/modules/c/nitf/shared/EXPLTA.c new file mode 100644 index 000000000..8ca339b80 --- /dev/null +++ b/modules/c/nitf/shared/EXPLTA.c @@ -0,0 +1,80 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + +NITF_CXX_GUARD + + +static nitf_TREDescription descrip_00087[] = { + {NITF_BCS_A, 3, "Angle to True North", "ANGLE_TO_NORTH" }, + {NITF_BCS_A, 3, "Squint Angle", "SQUINT_ANGLE" }, + {NITF_BCS_A, 3, "Imaging Mode", "MODE" }, + {NITF_BCS_A, 16, "reserved 1", "RESVD001" }, + {NITF_BCS_A, 2, "FP Grazing Angle", "GRAZE_ANG" }, + {NITF_BCS_A, 2, "FP Slope Angle", "SLOPE_ANG" }, + {NITF_BCS_A, 2, "Polarization", "POLAR" }, + {NITF_BCS_A, 5, "Pixels per Line", "NSAMP" }, + {NITF_BCS_A, 1, "reserved 2", "RESVD002" }, + {NITF_BCS_A, 1, "Sequence Number", "SEQ_NUM" }, + {NITF_BCS_A, 12, "Primary Target ID", "PRIME_ID" }, + {NITF_BCS_A, 15, "Primary Target BE Number", "PRIME_BE" }, + {NITF_BCS_A, 1, "reserved 3", "RESVD003" }, + {NITF_BCS_A, 2, "Number of Secondary Targets", "N_SEC" }, + {NITF_BCS_A, 2, "Commanded IPR", "IPR" }, + {NITF_BCS_A, 2, "reserved 4", "RESVD004" }, + {NITF_BCS_A, 2, "reserved 5", "RESVD005" }, + {NITF_BCS_A, 5, "reserved 6", "RESVD006" }, + {NITF_BCS_A, 8, "reserved 7", "RESVD007" }, + {NITF_END, 0, NULL, NULL} +}; + +static nitf_TREDescription descrip_00101[] = { + {NITF_BCS_A, 7, "Angle to True North", "ANGLE_TO_NORTH" }, + {NITF_BCS_A, 7, "Squint Angle", "SQUINT_ANGLE" }, + {NITF_BCS_A, 3, "Imaging Mode", "MODE" }, + {NITF_BCS_A, 16, "reserved 1", "RESVD001" }, + {NITF_BCS_A, 5, "FP Grazing Angle", "GRAZE_ANG" }, + {NITF_BCS_A, 5, "FP Slope Angle", "SLOPE_ANG" }, + {NITF_BCS_A, 2, "Polarization", "POLAR" }, + {NITF_BCS_A, 5, "Pixels per Line", "NSAMP" }, + {NITF_BCS_A, 1, "reserved 2", "RESVD002" }, + {NITF_BCS_A, 1, "Sequence Number", "SEQ_NUM" }, + {NITF_BCS_A, 12, "Primary Target ID", "PRIME_ID" }, + {NITF_BCS_A, 15, "Primary Target BE Number", "PRIME_BE" }, + {NITF_BCS_A, 1, "reserved 3", "RESVD003" }, + {NITF_BCS_A, 2, "Number of Secondary Target", "N_SEC" }, + {NITF_BCS_A, 2, "Commanded IPR", "IPR" }, + {NITF_END, 0, NULL, NULL} +}; + +/* Define the available descriptions and the default one */ +static nitf_TREDescriptionInfo descriptions[] = { + { "EXPLTA_87", descrip_00087, 87 }, + { "EXPLTA_101", descrip_00101, 101 }, + { NULL, NULL, NITF_TRE_DESC_NO_LENGTH } +}; +static nitf_TREDescriptionSet descriptionSet = { 0, descriptions }; + +NITF_DECLARE_PLUGIN(EXPLTA) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/EXPLTB.c b/modules/c/nitf/shared/EXPLTB.c new file mode 100644 index 000000000..7b2d689bd --- /dev/null +++ b/modules/c/nitf/shared/EXPLTB.c @@ -0,0 +1,52 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_A, 7, "Angle to True North", "ANGLE_TO_NORTH" }, + {NITF_BCS_A, 6, "Angle North Accuracy", "ANGLE_TO_NORTH_ACCY" }, + {NITF_BCS_A, 7, "Squint Angle", "SQUINT_ANGLE" }, + {NITF_BCS_A, 6, "Squint Angle Accuracy", "SQUINT_ANGLE_ACCY" }, + {NITF_BCS_A, 3, "Imaging Mode", "MODE" }, + {NITF_BCS_A, 16, "reserved 1", "RESVD001" }, + {NITF_BCS_A, 5, "FP Grazing Angle", "GRAZE_ANG" }, + {NITF_BCS_A, 5, "FP Grazing Angle Accur", "GRAZE_ANG_ACCY" }, + {NITF_BCS_A, 5, "FP Slope Angle", "SLOPE_ANG" }, + {NITF_BCS_A, 2, "Polarization", "POLAR" }, + {NITF_BCS_A, 5, "Pixels per Line", "NSAMP" }, + {NITF_BCS_A, 1, "reserved 2", "RESVD002" }, + {NITF_BCS_A, 1, "Sequence Number", "SEQ_NUM" }, + {NITF_BCS_A, 12, "Primary Target ID", "PRIME_ID" }, + {NITF_BCS_A, 15, "Primary Target BE Number", "PRIME_BE" }, + {NITF_BCS_A, 1, "reserved 3", "RESVD003" }, + {NITF_BCS_A, 2, "Number of Secondary Targets", "N_SEC" }, + {NITF_BCS_A, 2, "Commanded IPR", "IPR" }, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(EXPLTB, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/GEOLOB.c b/modules/c/nitf/shared/GEOLOB.c new file mode 100644 index 000000000..2285c9c97 --- /dev/null +++ b/modules/c/nitf/shared/GEOLOB.c @@ -0,0 +1,37 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_N, 9, "Longitude density", "ARV" }, + {NITF_BCS_N, 9, "Latitude density", "BRV" }, + {NITF_BCS_N, 15, "Longitude of Reference Origin", "LSO" }, + {NITF_BCS_N, 15, "Latitude of Reference Origin", "PSO" }, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(GEOLOB, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/GEOPSB.c b/modules/c/nitf/shared/GEOPSB.c new file mode 100644 index 000000000..3b1a44e1e --- /dev/null +++ b/modules/c/nitf/shared/GEOPSB.c @@ -0,0 +1,47 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_A, 3, "Coordinate System Type", "TYP" }, + {NITF_BCS_A, 3, "Coordinate Units", "UNI" }, + {NITF_BCS_A, 80, "Geodetic Datum Name", "DAG" }, + {NITF_BCS_A, 4, "Geodetic Datum Code", "DCD" }, + {NITF_BCS_A, 80, "Ellipsoid Name", "ELL" }, + {NITF_BCS_A, 3, "Ellipsoid Code", "ELC" }, + {NITF_BCS_A, 80, "Vertical Datum Reference", "DVR" }, + {NITF_BCS_A, 4, "Code of Vertical Reference", "VDCDVR" }, + {NITF_BCS_A, 80, "Sounding Datum Name", "SDA" }, + {NITF_BCS_A, 4, "Code for Sounding Datum", "VDCSDA" }, + {NITF_BCS_N, 15, "Z values False Origin", "ZOR" }, + {NITF_BCS_A, 3, "Grid Code", "GRD" }, + {NITF_BCS_A, 80, "Grid Description", "GRN" }, + {NITF_BCS_N, 4, "Grid Zone number", "ZNA" }, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(GEOPSB, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/GRDPSB.c b/modules/c/nitf/shared/GRDPSB.c new file mode 100644 index 000000000..2a193f8e2 --- /dev/null +++ b/modules/c/nitf/shared/GRDPSB.c @@ -0,0 +1,47 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_N, 2, "Number of Location Grids", "NUM_GRDS" }, + + {NITF_LOOP, 0, NULL, "NUM_GRDS"}, + + {NITF_BCS_N, 10, "Location Grid Elevation", "ZVL"}, + {NITF_BCS_A, 10, "Location Grid ID", "BAD"}, + {NITF_BCS_N, 12, "Data Density in Columns", "LOD"}, + {NITF_BCS_N, 12, "Data Density in Rows", "LAD"}, + {NITF_BCS_N, 11, "Origin in Columns", "LSO"}, + {NITF_BCS_N, 11, "Origin in Rows", "PSO"}, + + {NITF_ENDLOOP, 0, NULL, NULL }, + + {NITF_END, 0, NULL, NULL }, +}; + +NITF_DECLARE_SINGLE_PLUGIN(GRDPSB, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/HISTOA.c b/modules/c/nitf/shared/HISTOA.c new file mode 100644 index 000000000..5312c09ca --- /dev/null +++ b/modules/c/nitf/shared/HISTOA.c @@ -0,0 +1,123 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_A, 20, "System Type", "SYSTYPE" }, + {NITF_BCS_A, 12, "Prior Compression", "PC" }, + {NITF_BCS_A, 4, "Prior Enhancements", "PE" }, + {NITF_BCS_A, 1, "System Specific Remap", "REMAP_FLAG" }, + {NITF_BCS_N, 2, "Data Mapping ID from the ESD", "LUTID" }, + {NITF_BCS_N, 2, "Number of Processing Events", "NEVENTS" }, + {NITF_LOOP, 0, NULL, "NEVENTS" }, + + {NITF_BCS_A, 14, "Processing Date And Time", "PDATE" }, + {NITF_BCS_A, 10, "Processing Site", "PSITE" }, + {NITF_BCS_A, 10, "Softcopy Processing Application", "PAS" }, + {NITF_BCS_N, 1, "Number of Image Processing Comments", "NIPCOM" }, + + {NITF_LOOP, 0, NULL, "NIPCOM"}, + + {NITF_BCS_A, 80, "Image Processing Comment", "IPCOM" }, + + {NITF_ENDLOOP, 0, NULL, NULL}, + + {NITF_BCS_N, 2, "Input Bit Depth (actual)", "IBPP" }, + {NITF_BCS_A, 3, "Input Pixel Value Type", "IPVTYPE" }, + {NITF_BCS_A, 10, "Input Bandwidth Compression", "INBWC" }, + {NITF_BCS_A, 1, "Display-Ready Flag", "DISP_FLAG" }, + {NITF_BCS_N, 1, "Image Rotation", "ROT_FLAG" }, + + {NITF_IF, 0, "== 1", "ROT_FLAG" }, + + {NITF_BCS_A, 8, "Angle Rotation", "ROT_ANGLE" }, + + {NITF_ENDIF, 0, NULL, NULL}, + + {NITF_BCS_A, 1, "Image Projection", "ASYM_FLAG" }, + + {NITF_IF, 0, "eq 1", "ASYM_FLAG" }, + + {NITF_BCS_A, 7, "Mag in Line (row) Direction", "ZOOMROW" }, + {NITF_BCS_A, 7, "Mag in Element (column) Direction", "ZOOMCOL" }, + + {NITF_ENDIF, 0, NULL, NULL}, + + {NITF_BCS_A, 1, "Asymmetric Correction", "PROJ_FLAG" }, + + {NITF_BCS_N, 1, "Sharpening", "SHARP_FLAG" }, + + {NITF_IF, 0, "== 1", "SHARP_FLAG" }, + + {NITF_BCS_N, 2, "Sharpening Family Number", "SHARPFAM" }, + {NITF_BCS_N, 2, "Sharpening Member Number", "SHARPMEM" }, + + {NITF_ENDIF, 0, NULL, NULL}, + + {NITF_BCS_N, 1, "Symmetrical Magnification", "MAG_FLAG" }, + + {NITF_IF, 0, "== 1", "MAG_FLAG" }, + + {NITF_BCS_A, 7, "Level of Relative Magnification", "MAG_LEVEL" }, + + {NITF_ENDIF, 0, NULL, NULL}, + + + {NITF_BCS_N, 1, "Dynamic Range Adjustment (DRA)", "DRA_FLAG" }, + + {NITF_IF, 0, "== 1", "DRA_FLAG" }, + + {NITF_BCS_A, 7, "DRA Multiplier", "DRA_MULT" }, + + {NITF_BCS_N, 5, "DRA Subtractor", "DRA_SUB" }, + + {NITF_ENDIF, 0, NULL, NULL}, + + {NITF_BCS_N, 1, "Tonal Transfer Curve (TTC)", "TTC_FLAG" }, + + + {NITF_IF, 0, "== 1", "TTC_FLAG" }, + + {NITF_BCS_N, 2, "TTC Family Number", "TTCFAM" }, + + {NITF_BCS_N, 2, "TTC Member Number", "TTCMEM" }, + + {NITF_ENDIF, 0, NULL, NULL}, + + + {NITF_BCS_N, 1, "Device LUT", "DEVLUT_FLAG" }, + + + {NITF_BCS_N, 2, "Output Bit Depth (actual)", "OBPP" }, + {NITF_BCS_A, 3, "Output Pixel Value Type", "OPVTYPE" }, + {NITF_BCS_A, 10, "Output Bandwidth Compression", "OUTBWC" }, + + {NITF_ENDLOOP, 0, NULL, NULL}, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(HISTOA, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/ICHIPB.c b/modules/c/nitf/shared/ICHIPB.c new file mode 100644 index 000000000..d8117d210 --- /dev/null +++ b/modules/c/nitf/shared/ICHIPB.c @@ -0,0 +1,104 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_A, 2, "Non-linear transform flag", "XFRM_FLAG" }, + {NITF_BCS_A, 10, "Scale Factor Relative to RO", "SCALE_FACTOR" }, + {NITF_BCS_A, 2, "Anamorphic Correction Indicator", "ANAMRPH_CORR" }, + {NITF_BCS_A, 2, "Scan Block Number", "SCANBLK_NUM" }, + {NITF_BCS_A, 12, + "Output Product row number component of grid point index(1,1)", + "OP_ROW_11" }, + + {NITF_BCS_A, 12, + "Output product column number component of grid point index(1,1)", + "OP_COL_11" }, + + {NITF_BCS_A, 12, + "Output product row number component of grid point index(1,2)", + "OP_ROW_12" }, + + {NITF_BCS_A, 12, + "Output product column number component of grid point index(1,2)", + "OP_COL_12" }, + + {NITF_BCS_A, 12, + "Output product row number component of grid point index(2,1)", + "OP_ROW_21" }, + + {NITF_BCS_A, 12, + "Output product column number component of grid point index(2,1)", + "OP_COL_21" }, + + {NITF_BCS_A, 12, + "Output product row number component of grid point index(2,2)", + "OP_ROW_22" }, + + {NITF_BCS_A, 12, + "Output product column number component of grid point index(2,2)", + "OP_COL_22" }, + + {NITF_BCS_A, 12, + "Grid point (1,1) row number in full image coodinates", + "FI_ROW_11" }, + + {NITF_BCS_A, 12, + "Grid point (1,1) column number in full image coodinates", + "FI_COL_11" }, + + {NITF_BCS_A, 12, + "Grid point (1,2) row number in full image coodinates", + "FI_ROW_12" }, + + {NITF_BCS_A, 12, + "Grid point (1,2) column number in full image coodinates", + "FI_COL_12" }, + + {NITF_BCS_A, 12, + "Grid point (2,1) row number in full image coodinates", + "FI_ROW_21" }, + + {NITF_BCS_A, 12, + "Grid point (2,1) column number in full image coodinates", + "FI_COL_21" }, + + {NITF_BCS_A, 12, + "Grid point (2,2) row number in full image coodinates", + "FI_ROW_22" }, + + {NITF_BCS_A, 12, + "Grid point (2,2) column number in full image coodinates", + "FI_COL_22" }, + + {NITF_BCS_A, 8,"Full image number of rows","FI_ROW" }, + {NITF_BCS_A, 8, "Full image number of columns", "FI_COL" }, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(ICHIPB, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/IMGDTA.c b/modules/c/nitf/shared/IMGDTA.c new file mode 100644 index 000000000..036063fc8 --- /dev/null +++ b/modules/c/nitf/shared/IMGDTA.c @@ -0,0 +1,101 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +/* FIXME This plugin clobbers its own variables! + May need revision using 2.0 API to support + */ +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_N, 4, "VERNUM", "VERNUM" }, + {NITF_BCS_A, 32, "FILENAME", "FILENAME" }, + {NITF_BCS_A, 32, "PARENT_FNAME", "PARENT_FNAME" }, + {NITF_BCS_A, 32, "CHECKSUM", "CHECKSUM" }, + {NITF_BCS_N, 10, "ISIZE", "ISIZE" }, + {NITF_BCS_A, 1, "STATUS", "STATUS" }, + {NITF_BCS_A, 8, "CDATE", "CDATE" }, + {NITF_BCS_A, 10, "CTIME", "CTIME" }, + {NITF_BCS_A, 8, "PDATE", "PDATE" }, + {NITF_BCS_A, 1, "SENTYPE", "SENTYPE" }, + {NITF_BCS_A, 1, "DATA_PLANE", "DATA_PLANE" }, + {NITF_BCS_A, 4, "DATA_TYPE", "DATA_TYPE" }, + {NITF_BCS_N, 6, "NUM_ROWS", "NUM_ROWS" }, + {NITF_BCS_N, 6, "NUM_COLS", "NUM_COLS" }, + {NITF_BCS_A, 1, "SEN_POS", "SEN_POS" }, + {NITF_BCS_A, 15, "SEN_CAL_FAC", "SEN_CAL_FAC" }, + {NITF_BCS_A, 50, "IMGQUAL", "IMGQUAL" }, + {NITF_BCS_N, 2, "NUM_VER", "NUM_VER" }, + {NITF_LOOP, 0, NULL, "NUM_VER"}, + {NITF_BCS_A, 15, "VER_NAME", "VER_NAME" }, + {NITF_BCS_N, 10, "VERNUM", "VERNUM" }, + {NITF_ENDLOOP, 0, NULL, NULL}, + {NITF_IF, 0, "eq R", "SENTYPE"}, + {NITF_BCS_A, 1, "SEN_LOOK", "SEN_LOOK" }, + {NITF_BCS_A, 7, "CR_RES", "CR_RES" }, + {NITF_BCS_A, 7, "RANGE_RES", "RANGE_RES" }, + {NITF_BCS_A, 7, "CR_PIXELSP", "CR_PIXELSP" }, + {NITF_BCS_A, 7, "RANGE_PIXELSP", "RANGE_PIXELSP" }, + {NITF_BCS_A, 40, "CR_WEIGHT", "CR_WEIGHT" }, + {NITF_BCS_A, 40, "RANGE_WEIGHT", "RANGE_WEIGHT" }, + {NITF_BCS_A, 6, "R_OVR_SAMP", "R_OVR_SAMP" }, + {NITF_BCS_A, 6, "CR_OVR_SAMP", "CR_OVR_SAMP" }, + {NITF_BCS_A, 6, "D_DEPRES", "D_DEPRES" }, + {NITF_BCS_A, 7, "D_GP_SQ", "D_GP_SQ" }, + {NITF_BCS_A, 7, "D_SP_SQ", "D_SP_SQ" }, + {NITF_BCS_A, 7, "D_RANGE", "D_RANGE" }, + {NITF_BCS_A, 21, "D_AP_LL", "D_AP_LL" }, + {NITF_BCS_A, 7, "D_AP_ELV", "D_AP_ELV" }, + {NITF_BCS_A, 6, "M_DEPRES", "M_DEPRES" }, + {NITF_BCS_A, 7, "M_GP_SQ", "M_GP_SQ" }, + {NITF_BCS_A, 7, "M_SP_SQ", "M_SP_SQ" }, + {NITF_BCS_A, 7, "M_RANGE", "M_RANGE" }, + {NITF_BCS_A, 21, "M_AP_LL", "M_AP_LL" }, + {NITF_BCS_A, 7, "M_AP_ELV", "M_AP_ELV" }, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq E", "SENTYPE"}, + {NITF_BCS_A, 6, "GRNDSAMPDIS", "GRNDSAMPDIS" }, + {NITF_BCS_A, 6, "SWATHSIZE", "SWATHSIZE" }, + {NITF_BCS_A, 7, "D_RANGE", "D_RANGE" }, + {NITF_BCS_A, 6, "D_AZ_LOOK", "D_AZ_LOOK" }, + {NITF_BCS_A, 5, "D_EL_LOOK", "D_EL_LOOK" }, + {NITF_BCS_A, 7, "M_RANGE", "M_RANGE" }, + {NITF_BCS_A, 6, "M_AZ_LOOK", "M_AZ_LOOK" }, + {NITF_BCS_A, 5, "M_EL_LOOK", "M_EL_LOOK" }, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq I", "SENTYPE"}, + {NITF_BCS_A, 6, "GRNDSAMPDIS", "GRNDSAMPDIS" }, + {NITF_BCS_A, 6, "SWATHSIZE", "SWATHSIZE" }, + {NITF_BCS_A, 7, "D_RANGE", "D_RANGE" }, + {NITF_BCS_A, 6, "D_AZ_LOOK", "D_AZ_LOOK" }, + {NITF_BCS_A, 5, "D_EL_LOOK", "D_EL_LOOK" }, + {NITF_BCS_A, 7, "M_RANGE", "M_RANGE" }, + {NITF_BCS_A, 6, "M_AZ_LOOK", "M_AZ_LOOK" }, + {NITF_BCS_A, 5, "M_EL_LOOK", "M_EL_LOOK" }, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(IMGDTA, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/IOMAPA.c b/modules/c/nitf/shared/IOMAPA.c new file mode 100644 index 000000000..32d69b853 --- /dev/null +++ b/modules/c/nitf/shared/IOMAPA.c @@ -0,0 +1,88 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include +NITF_CXX_GUARD + +static nitf_TREDescription descrip_00006[] = { + {NITF_BCS_N, 3, "Band Identifier", "BAND_NUMBER" }, + {NITF_BCS_N, 1, "Mapping Method to Apply", "MAP_SELECT" }, + {NITF_BCS_N, 2, "Scale Factor 2", "S2" }, + {NITF_END, 0, NULL, NULL} +}; + +static nitf_TREDescription descrip_08202[] = { + {NITF_BCS_N, 3, "Band Identifier", "BAND_NUMBER" }, + {NITF_BCS_N, 1, "Mapping Method to Apply", "MAP_SELECT" }, + {NITF_BCS_N, 2, "I/O TABLE USED", "TABLE_ID" }, + {NITF_BCS_N, 2, "Scale Factor 1", "S1" }, + {NITF_BCS_N, 2, "Scale Factor 2", "S2" }, + {NITF_LOOP, 0, NITF_CONST_N, "4096"}, + {NITF_BCS_N, 2, "Output Mapping Value", "OUTPUT_MAP_VALUE" }, + {NITF_ENDLOOP, 0, NULL, NULL}, + {NITF_END, 0, NULL, NULL} +}; + +static nitf_TREDescription descrip_00016[] = { + {NITF_BCS_N, 3, "Band Identifier", "BAND_NUMBER" }, + {NITF_BCS_N, 1, "Mapping Method to Apply", "MAP_SELECT" }, + {NITF_BCS_N, 2, "I/O TABLE USED", "TABLE_ID" }, + {NITF_BCS_N, 2, "Scale Factor 1", "S1" }, + {NITF_BCS_N, 2, "Scale Factor 2", "S2" }, + {NITF_BCS_N, 3, "R Scaling Factor � Whole Part", "R_WHOLE" }, + {NITF_BCS_N, 3, "R Scaling Factor � Fractional Part" , "R_FRACTION" }, + {NITF_END, 0, NULL, NULL} +}; + +static nitf_TREDescription descrip_00091[] = { + {NITF_BCS_N, 3, "Band Identifier", "BAND_NUMBER" }, + {NITF_BCS_N, 1, "Mapping Method to Apply", "MAP_SELECT" }, + {NITF_BCS_N, 1, "I/O TABLE USED", "TABLE_ID" }, + {NITF_BCS_N, 2, "Scale Factor 1", "S1" }, + {NITF_BCS_N, 2, "Scale Factor 2", "S2" }, + {NITF_BCS_N, 1, "Number of Segments", "NO_OF_SEGMENTS" }, + {NITF_BCS_N, 4, "Segment Boundary 1", "XOB_1" }, + {NITF_BCS_N, 4, "Segment Boundary 2", "XOB_2" }, + {NITF_LOOP, 0, NULL, "NO_OF_SEGMENTS"}, + {NITF_BINARY, 4, "B0 Coefficient", "OUT_B0" }, + {NITF_BINARY, 4, "B1 Coefficient", "OUT_B1" }, + {NITF_BINARY, 4, "B2 Coefficient", "OUT_B2" }, + {NITF_BINARY, 4, "B3 Coefficient", "OUT_B3" }, + {NITF_BINARY, 4, "B4 Coefficient", "OUT_B4" }, + {NITF_BINARY, 4, "B5 Coefficient", "OUT_B5" }, + {NITF_ENDLOOP, 0, NULL, NULL}, + {NITF_END, 0, NULL, NULL} +}; + +/* Define the available descriptions and the default one */ +static nitf_TREDescriptionInfo descriptions[] = { + { "IOMAPA_6", descrip_00006, 6 }, + { "IOMAPA_8202", descrip_08202, 8202 }, + { "IOMAPA_16", descrip_00016, 16 }, + { "IOMAPA_91", descrip_00091, 91 }, + { NULL, NULL, NITF_TRE_DESC_NO_LENGTH } +}; +static nitf_TREDescriptionSet descriptionSet = { 0, descriptions }; + +NITF_DECLARE_PLUGIN(IOMAPA) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/J2KLRA.c b/modules/c/nitf/shared/J2KLRA.c new file mode 100644 index 000000000..dc2642218 --- /dev/null +++ b/modules/c/nitf/shared/J2KLRA.c @@ -0,0 +1,60 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + + +#include + +NITF_CXX_GUARD + + +static nitf_TREDescription description[] = { + {NITF_BCS_N, 1, "original compressed data", "ORIG" }, + {NITF_BCS_N, 2, "number wavelet levels", "NLEVELS_O" }, + {NITF_BCS_N, 5, "number bands", "NBANDS_O" }, + {NITF_BCS_N, 3, "number layers", "NLAYERS_O" }, + {NITF_LOOP, 0, 0, "NLAYERS_O"}, + {NITF_BCS_N, 3, "layer ID number", "LAYER_ID" }, + {NITF_BCS_A, 9, "bitrate", "BITRATE" }, + {NITF_ENDLOOP, 0, NULL, NULL}, + /* These fields only appear if it's a parsed stream + * (i.e. ORIG is 1, 3, or 9) */ + {NITF_IF, 0, "== 1", "ORIG"}, + {NITF_BCS_N, 2, "number wavelet levels", "NLEVELS_I" }, + {NITF_BCS_N, 5, "number bands", "NBANDS_I" }, + {NITF_BCS_N, 3, "number layers", "NLAYERS_I" }, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "== 3", "ORIG"}, + {NITF_BCS_N, 2, "number wavelet levels", "NLEVELS_I" }, + {NITF_BCS_N, 5, "number bands", "NBANDS_I" }, + {NITF_BCS_N, 3, "number layers", "NLAYERS_I" }, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "== 9", "ORIG"}, + {NITF_BCS_N, 2, "number wavelet levels", "NLEVELS_I" }, + {NITF_BCS_N, 5, "number bands", "NBANDS_I" }, + {NITF_BCS_N, 3, "number layers", "NLAYERS_I" }, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(J2KLRA, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/JITCID.c b/modules/c/nitf/shared/JITCID.c new file mode 100644 index 000000000..fe342d557 --- /dev/null +++ b/modules/c/nitf/shared/JITCID.c @@ -0,0 +1,35 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_A, NITF_TRE_GOBBLE, "File Comment", "FILCMT" }, + {NITF_END, 0, NULL, NULL} +}; +NITF_DECLARE_SINGLE_PLUGIN(JITCID, description) + + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/MAPLOB.c b/modules/c/nitf/shared/MAPLOB.c new file mode 100644 index 000000000..5ea58c015 --- /dev/null +++ b/modules/c/nitf/shared/MAPLOB.c @@ -0,0 +1,38 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_A, 3, "Length units", "UNILOA" }, + {NITF_BCS_N, 5, "Easting interval", "LOD" }, + {NITF_BCS_N, 5, "Northing interval", "LAD" }, + {NITF_BCS_N, 15, "Easting of Reference Origin", "LSO" }, + {NITF_BCS_N, 15, "Northing of Reference Origin", "PSO" }, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(MAPLOB, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/MENSRA.c b/modules/c/nitf/shared/MENSRA.c new file mode 100644 index 000000000..782e654ac --- /dev/null +++ b/modules/c/nitf/shared/MENSRA.c @@ -0,0 +1,116 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + + +#include + +NITF_CXX_GUARD + + +static nitf_TREDescription descrip_00155[] = { + {NITF_BCS_A, 21, "CCRP Location", "CCRP_LOC" }, + {NITF_BCS_A, 6, "CCRP Altitude", "CCRP_ALT" }, + {NITF_BCS_A, 7, "Range Offset Between CCRP and Patch Center", "OF_PC_R" }, + {NITF_BCS_A, 7, "Azimuth Offset Between CCRP and Patch Center", "OF_PC_A" }, + {NITF_BCS_A, 7, "Cosine of Grazing Angle", "COSGRZ" }, + {NITF_BCS_A, 7, "Range to CCRP", "RGCCRP" }, + {NITF_BCS_A, 1, "Right/Left Map", "RLMAP" }, + {NITF_BCS_A, 5, "CCRP Row Number", "CCRP_ROW" }, + {NITF_BCS_A, 5, "CCRP Col Number", "CCRP_COL" }, + {NITF_BCS_A, 21, "Aircraft Location", "ACFT_LOC" }, + {NITF_BCS_A, 5, "Aircraft Altitude", "ACFT_ALT" }, + {NITF_BCS_A, 7, "Range Unit Vector North", "C_R_NC" }, + {NITF_BCS_A, 7, "Range Unit Vector East", "C_R_EC" }, + {NITF_BCS_A, 7, "Range Unit Vector Down", "C_R_DC" }, + {NITF_BCS_A, 7, "Azimuth Unit Vect North", "C_AZ_NC" }, + {NITF_BCS_A, 7, "Azimuth Unit Vect East", "C_AZ_EC" }, + {NITF_BCS_A, 7, "Azimuth Unit Vect Down", "C_AZ_DC" }, + {NITF_BCS_A, 7, "Altitude North", "C_AL_NC" }, + {NITF_BCS_A, 7, "Altitude East", "C_AL_EC" }, + {NITF_BCS_A, 7, "Altitude Down", "C_AL_DC" }, + {NITF_END, 0, NULL, NULL} +}; + +static nitf_TREDescription descrip_00174[] = { + {NITF_BCS_A, 21, "Aircraft Location", "ACFT_LOC" }, + {NITF_BCS_A, 6, "Aircraft Altitude", "ACFT_ALT" }, + {NITF_BCS_A, 21, "CCRP Location", "CCRP_LOC" }, + {NITF_BCS_A, 6, "CCRP Altitude", "CCRP_ALT" }, + {NITF_BCS_A, 7, "Range Offset Between CCRP and Patch Center", "OF_PC_R" }, + {NITF_BCS_A, 7, "Azimuth Offset Between CCRP and Patch Center", "OF_PC_A" }, + {NITF_BCS_A, 7, "Cos of Grazing Angle", "COSGRZ" }, + {NITF_BCS_A, 7, "Range to CCRP", "RGCCRP" }, + {NITF_BCS_A, 1, "Right/Left Map", "RLMAP" }, + {NITF_BCS_A, 5, "CCRP Row Number", "CCRP_ROW" }, + {NITF_BCS_A, 5, "CCRP Col Number", "CCRP_COL" }, + {NITF_BCS_A, 9, "Range Unit Vector North", "C_R_NC" }, + {NITF_BCS_A, 9, "Range Unit Vector East", "C_R_EC" }, + {NITF_BCS_A, 9, "Range Unit Vector Down", "C_R_DC" }, + {NITF_BCS_A, 9, "Azimuth Unit Vect North", "C_AZ_NC" }, + {NITF_BCS_A, 9, "Azimuth Unit Vect East", "C_AZ_EC" }, + {NITF_BCS_A, 9, "Azimuth Unit Vect Down", "C_AZ_DC" }, + {NITF_BCS_A, 9, "Altitude North", "C_AL_NC" }, + {NITF_BCS_A, 9, "Altitude East", "C_AL_EC" }, + {NITF_BCS_A, 9, "Altitude Down", "C_AL_DC" }, + {NITF_END, 0, NULL, NULL} +}; + +static nitf_TREDescription descrip_00185[] = { + {NITF_BCS_A, 25, "Aircraft Location", "ACFT_LOC" }, + {NITF_BCS_A, 6, "Aircraft Altitude", "ACFT_ALT" }, + {NITF_BCS_A, 25, "CCRP Location", "CCRP_LOC" }, + {NITF_BCS_A, 6, "CCRP Altitude", "CCRP_ALT" }, + {NITF_BCS_A, 7, "Range Offset Between CCRP and Patch Center", "OF_PC_R" }, + {NITF_BCS_A, 7, "Azimuth Offset Between CCRP and Patch Center", "OF_PC_A" }, + {NITF_BCS_A, 7, "Cos of Grazing Angle", "COSGZ" }, + {NITF_BCS_A, 7, "Range to CCRP", "RGCCRP" }, + {NITF_BCS_A, 1, "Right/Left Map", "RLMAP" }, + {NITF_BCS_A, 5, "CCRP Row Number", "CCRP_ROW" }, + {NITF_BCS_A, 5, "CCRP Col Number", "CCRP_COL" }, + {NITF_BCS_A, 10, "Range Unit Vector North", "C_R_NC" }, + {NITF_BCS_A, 10, "Range Unit Vector East", "C_R_EC" }, + {NITF_BCS_A, 10, "Range Unit Vector Down", "C_R_DC" }, + {NITF_BCS_A, 9, "Azimuth Unit Vect North", "C_AZ_NC" }, + {NITF_BCS_A, 9, "Azimuth Unit Vect East", "C_AZ_EC" }, + {NITF_BCS_A, 9, "Azimuth Unit Vect Down", "C_AZ_DC" }, + {NITF_BCS_A, 9, "Altitude North", "C_AL_NC" }, + {NITF_BCS_A, 9, "Altitude East", "C_AL_EC" }, + {NITF_BCS_A, 9, "Altitude Down", "C_AL_DC" }, + {NITF_BCS_A, 3, "Total Number of Tiles in Column Direction", + "TOTAL_TILES_COLS" }, + {NITF_BCS_A, 5, "Total Number of Tiles in Row direction", + "TOTAL_TILES_ROWS" }, + {NITF_END, 0, NULL, NULL} +}; + +/* Define the available descriptions and the default one */ +static nitf_TREDescriptionInfo descriptions[] = { + { "MENSRA_155", descrip_00155, 155 }, + { "MENSRA_174", descrip_00174, 174 }, + { "MENSRA_185", descrip_00185, 185 }, + { NULL, NULL, NITF_TRE_DESC_NO_LENGTH } +}; +static nitf_TREDescriptionSet descriptionSet = { 0, descriptions }; + +NITF_DECLARE_PLUGIN(MENSRA) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/MENSRB.c b/modules/c/nitf/shared/MENSRB.c new file mode 100644 index 000000000..3202ee9db --- /dev/null +++ b/modules/c/nitf/shared/MENSRB.c @@ -0,0 +1,60 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_A, 25, "Aircraft Location", "ACFT_LOC" }, + {NITF_BCS_A, 6, "Aircraft Location Accuracy", "ACFT_LOC_ACCY" }, + {NITF_BCS_A, 6, "Aircraft Altitude", "ACFT_ALT" }, + {NITF_BCS_A, 25, "Reference Point Location", "RP_LOC" }, + {NITF_BCS_A, 6, "Reference Point Location Accuracy", "RP_LOC_ACCY" }, + {NITF_BCS_A, 6, "Reference Point Elevation", "RP_ELV" }, + {NITF_BCS_A, 7, "Range Offset", "OF_PC_R" }, + {NITF_BCS_A, 7, "Azimuth Offset", "OF_PC_A" }, + {NITF_BCS_A, 7, "Cosine of Grazing Angle", "COSGRZ" }, + {NITF_BCS_A, 7, "Estimated Slant Range", "RGCRP" }, + {NITF_BCS_A, 1, "Right/Left Map", "RLMAP" }, + {NITF_BCS_A, 5, "RP Row Number", "RP_ROW" }, + {NITF_BCS_A, 5, "RP Column Number", "RP_COL" }, + {NITF_BCS_A, 10, "Range Unit Vector North","C_R_NC" }, + {NITF_BCS_A, 10, "Range Unit Vector East", "C_R_EC" }, + {NITF_BCS_A, 10, "Range Unit Vector Down", "C_R_DC" }, + {NITF_BCS_A, 9, "Azimuth Unit Vect North", "C_AZ_NC" }, + {NITF_BCS_A, 9, "Azimuth Unit Vect East", "C_AZ_EC" }, + {NITF_BCS_A, 9, "Azimuth Unit Vect Down", "C_AZ_DC" }, + {NITF_BCS_A, 9, "Altitude North", "C_AL_NC" }, + {NITF_BCS_A, 9, "Altitude East", "C_AL_EC" }, + {NITF_BCS_A, 9, "Altitude Down", "C_AL_DC" }, + {NITF_BCS_A, 3, "Total Number of Tiles in Column Direction", + "TOTAL_TILES_COLS" }, + {NITF_BCS_A, 5, "Total Number of Tiles in Row Direction", + "TOTAL_TILES_ROWS" }, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(MENSRB, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/MPDSRA.c b/modules/c/nitf/shared/MPDSRA.c new file mode 100644 index 000000000..63b243f89 --- /dev/null +++ b/modules/c/nitf/shared/MPDSRA.c @@ -0,0 +1,61 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +/* + * FIXME, these names dont seem right + */ +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_A, 2, "Image Block Number", "blkno" }, + {NITF_BCS_A, 2, "Commanded IPR", "cdipr" }, + {NITF_BCS_N, 2, "No of Blocks in WDG", "nblkw" }, + {NITF_BCS_N, 5, "No of Rows in Block", "nrblk" }, + {NITF_BCS_N, 5, "No of Cols in Block", "ncblk" }, + {NITF_BCS_A, 9, "Output Ref Pt X (ECF)", "orpx" }, + {NITF_BCS_A, 9, "Output Ref Pt Y (ECF)", "orpy" }, + {NITF_BCS_A, 9, "Output Ref Pt Z (ECF)", "orpz" }, + {NITF_BCS_N, 5, "Row of ORP", "orpro" }, + {NITF_BCS_N, 5, "Col of ORP", "orpco" }, + {NITF_BCS_A, 7, "FP Normal Vector X", "fpnvx" }, + {NITF_BCS_A, 7, "FP Normal Vector Y", "fpnvy" }, + {NITF_BCS_A, 7, "FP Normal Vector Z", "fpnvz" }, + {NITF_BCS_A, 9, "Collection Start Time", "arptm" }, + {NITF_BCS_A, 14, "reserved 1", "resv1" }, + {NITF_BCS_A, 9, "Aircraft Position N", "arppn" }, + {NITF_BCS_A, 9, "Aircraft Position E", "arppe" }, + {NITF_BCS_A, 9, "Aircraft Position D", "arppd" }, + {NITF_BCS_A, 9, "Aircraft Velocity N", "arpvn" }, + {NITF_BCS_A, 9, "Aircraft Velocity E", "arpve" }, + {NITF_BCS_A, 9, "Aircraft Velocity D", "arpvd" }, + {NITF_BCS_A, 8, "Aircraft Accel N", "arpan" }, + {NITF_BCS_A, 8, "Aircraft Accel E", "arpae" }, + {NITF_BCS_A, 8, "Aircraft Accel D", "arpad" }, + {NITF_BCS_A, 13, "reserved 2", "resv2" }, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(MPDSRA, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/MSTGTA.c b/modules/c/nitf/shared/MSTGTA.c new file mode 100644 index 000000000..65646f576 --- /dev/null +++ b/modules/c/nitf/shared/MSTGTA.c @@ -0,0 +1,46 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + + +#include +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_A, 5, "TGT NUM", "TGTNUM" }, + {NITF_BCS_A, 12, "TGT ID", "TGTID" }, + {NITF_BCS_A, 15, "TGT BE", "TGTBE" }, + {NITF_BCS_A, 3, "TGT PRI", "TGTPRI" }, + {NITF_BCS_A, 12, "TGT REQ", "TGTREQ" }, + {NITF_BCS_A, 12, "TGT LTIOV", "TGTLTIOV" }, + {NITF_BCS_A, 1, "TGT TYPE", "TGTTYPE" }, + {NITF_BCS_A, 1, "TGT COLL", "TGTCOLL" }, + {NITF_BCS_A, 5, "TGT CAT", "TGTCAT" }, + {NITF_BCS_A, 7, "TGT UTC", "TGTUTC" }, + {NITF_BCS_A, 6, "TGT EVEL", "TGTEVEL" }, + {NITF_BCS_A, 1, "TGT EVEL UNIT", "TGTEVELUNIT" }, + {NITF_BCS_A, 21, "TGT LOC", "TGTLOC" }, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(MSTGTA, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/MTIRPA.c b/modules/c/nitf/shared/MTIRPA.c new file mode 100644 index 000000000..4ee8cf00a --- /dev/null +++ b/modules/c/nitf/shared/MTIRPA.c @@ -0,0 +1,53 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +/* + * FIXME: these names look wrong + */ +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_A, 2, "Destination Point", "destp" }, + {NITF_BCS_A, 3, "MTI Packet ID No.", "mtpid" }, + {NITF_BCS_A, 4, "Patch Number", "pchno" }, + {NITF_BCS_A, 5, "WAMTI Frame Number", "wamfn" }, + {NITF_BCS_A, 1, "WAMTI Bar Number", "wambn" }, + {NITF_BCS_A, 8, "UTC", "utc" }, + {NITF_BCS_A, 5, "Squint Angle", "sqnta" }, + {NITF_BCS_A, 7, "Cos of Grazing Angle", "cosgz" }, + {NITF_BCS_N, 3, "Number of Valid Targets", "nvtgt" }, + {NITF_LOOP, 0, NULL, "nvtgt"}, + {NITF_BCS_A, 21, "Target Location", "tgloc" }, + {NITF_BCS_A, 4, "Target Radial Velocity", "tgrdv" }, + {NITF_BCS_A, 3, "Target Estim Gnd Speed", "tggsp" }, + {NITF_BCS_A, 3, "Target Heading", "tghea" }, + {NITF_BCS_A, 2, "Target Signal Amplitude", "tgsig" }, + {NITF_BCS_A, 1, "Target Category", "tgcat" }, + {NITF_ENDLOOP, 0, NULL, NULL}, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(MTIRPA, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/MTIRPB.c b/modules/c/nitf/shared/MTIRPB.c new file mode 100644 index 000000000..79c39b79d --- /dev/null +++ b/modules/c/nitf/shared/MTIRPB.c @@ -0,0 +1,59 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +/* + * FIXME: These names seem wrong + */ +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_A, 2, "Destination Point", "destp" }, + {NITF_BCS_A, 3, "MTI Packet ID No.", "mtpid" }, + {NITF_BCS_A, 4, "Patch Number", "pchno" }, + {NITF_BCS_A, 5, "WAMTI Frame Number", "wamfn" }, + {NITF_BCS_A, 1, "WAMTI Bar Number", "wambn" }, + {NITF_BCS_A, 14, "Date/Time", "utc" }, + {NITF_BCS_A, 21, "Acft Loc", "acloc" }, + {NITF_BCS_A, 6, "Acft Alt", "acalt" }, + {NITF_BCS_A, 1, "Acft Alt Unit", "acalu" }, + {NITF_BCS_A, 3, "Acft Heading", "ached" }, + {NITF_BCS_A, 1, "MTI LR", "mtilr" }, + {NITF_BCS_A, 5, "Squint Angle", "sqnta" }, + {NITF_BCS_A, 7, "Cos of Grazing Angle", "cosgz" }, + {NITF_BCS_N, 3, "Number of Valid Targets", "nvtgt" }, + {NITF_LOOP, 0, NULL, "nvtgt"}, + {NITF_BCS_A, 23, "Target Location", "tgloc" }, + {NITF_BCS_A, 6, "Target Locatn Accuracy", "tglca" }, + {NITF_BCS_A, 4, "Target Radial Velocity", "tgrdv" }, + {NITF_BCS_A, 3, "Target Estim Gnd Speed", "tggsp" }, + {NITF_BCS_A, 3, "Target Heading", "tghea" }, + {NITF_BCS_A, 2, "Target Signal Amplitude", "tgsig" }, + {NITF_BCS_A, 1, "Target Category", "tgcat" }, + {NITF_ENDLOOP, 0, NULL, NULL}, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(MTIRPB, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/NBLOCA.c b/modules/c/nitf/shared/NBLOCA.c new file mode 100644 index 000000000..e3d381d56 --- /dev/null +++ b/modules/c/nitf/shared/NBLOCA.c @@ -0,0 +1,38 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BINARY, 4, "First Image Frame Offset", "FRAME_1_OFFSET" }, + {NITF_BINARY, 4, "Number of Blocks", "NUMBER_OF_FRAMES" }, + {NITF_LOOP, 0, "- 1", "NUMBER_OF_FRAMES"}, + {NITF_BINARY, 4, "Number of Blocks", "FRAME_OFFSET" }, + {NITF_ENDLOOP, 0, NULL, NULL}, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(NBLOCA, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/OBJCTA.c b/modules/c/nitf/shared/OBJCTA.c new file mode 100644 index 000000000..30ae55ca0 --- /dev/null +++ b/modules/c/nitf/shared/OBJCTA.c @@ -0,0 +1,70 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_N, 4, "VERNUM", "VERNUM" }, + {NITF_BCS_N, 3, "NUM_OBJ", "NUM_OBJ" }, + {NITF_BCS_A, 10, "OBJ_REF", "OBJ_REF" }, + {NITF_BCS_N, 3, "NUM_SCENE_OBJ", "NUM_SCENE_OBJ" }, + {NITF_LOOP, 0, NULL, "NUM_OBJ"}, + {NITF_BCS_A, 20, "OBJ_TY", "OBJ_TY" }, + {NITF_BCS_A, 15, "OBJ_NM", "OBJ_NM" }, + {NITF_BCS_A, 2, "OBJ_POS", "OBJ_POS" }, + {NITF_BCS_A, 10, "OBJ_SN", "OBJ_SN" }, + {NITF_BCS_A, 21, "OBJ_LL", "OBJ_LL" }, + {NITF_BCS_A, 8, "OBJ_ELEV", "OBJ_ELEV" }, + {NITF_BCS_A, 8, "OBJ_ROW", "OBJ_ROW" }, + {NITF_BCS_A, 8, "OBJ_COL", "OBJ_COL" }, + {NITF_BCS_A, 8, "OBJ_PROW", "OBJ_PROW" }, + {NITF_BCS_A, 8, "OBJ_PCOL", "OBJ_PCOL" }, + {NITF_BCS_A, 20, "OBJ_ATTR", "OBJ_ATTR" }, + {NITF_BCS_A, 2, "OBJ_SEN", "OBJ_SEN" }, + {NITF_IF, 0, "eq R ", "OBJ_SEN"}, + {NITF_BCS_A, 7, "OBJ_AZ_3DB_WIDTH", "OBJ_AZ_3DB_WIDTH" }, + {NITF_BCS_A, 7, "OBJ_RNG_3DB_WIDTH", "OBJ_RNG_3DB_WIDTH" }, + {NITF_BCS_A, 7, "OBJ_AZ_18DB_WIDTH", "OBJ_AZ_18DB_WIDTH" }, + {NITF_BCS_A, 7, "OBJ_RNG_18DB_WIDTH", "OBJ_RNG_18DB_WIDTH" }, + {NITF_BCS_A, 8, "OBJ_AZ_3_18DB_RATIO", "OBJ_AZ_3_18DB_RATIO" }, + {NITF_BCS_A, 8, "OBJ_RNG_3_18DB_RATIO", "OBJ_RNG_3_18DB_RATIO" }, + {NITF_BCS_A, 8, "OBJ_AZ_PK_SL_RATIO", "OBJ_AZ_PK_SL_RATIO" }, + {NITF_BCS_A, 8, "OBJ_RNG_PK_SL_RATIO", "OBJ_RNG_PK_SL_RATIO" }, + {NITF_BCS_A, 8, "OBJ_AZ_INT_SL_RATIO", "OBJ_AZ_INT_SL_RATIO" }, + {NITF_BCS_A, 8, "OBJ_RNGINT_SL_RATIO", "OBJ_RNGINT_SL_RATIO" }, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq EO", "OBJ_SEN"}, + {NITF_BCS_A, 6, "OBJ_CAL_TEMP", "OBJ_CAL_TEMP" }, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq IR", "OBJ_SEN"}, + {NITF_BCS_A, 6, "OBJ_CAL_TEMP", "OBJ_CAL_TEMP" }, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_ENDLOOP, 0, NULL, NULL}, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(OBJCTA, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/OFFSET.c b/modules/c/nitf/shared/OFFSET.c new file mode 100644 index 000000000..9c5243289 --- /dev/null +++ b/modules/c/nitf/shared/OFFSET.c @@ -0,0 +1,35 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_N, 8, "Align-Scan Offset of First Pixel", "LINE" }, + {NITF_BCS_N, 8, "Cross-Scan Offset of First Pixel", "SAMPLE" }, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(OFFSET, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/PATCHA.c b/modules/c/nitf/shared/PATCHA.c new file mode 100644 index 000000000..a805158d1 --- /dev/null +++ b/modules/c/nitf/shared/PATCHA.c @@ -0,0 +1,82 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + +NITF_CXX_GUARD + + +static nitf_TREDescription descrip_00074[] = { + {NITF_BCS_A, 4, "Patch Number", "PAT_NO" }, + {NITF_BCS_A, 1, "Last Patch of Search Scene", "LAST_PAT_FLAG" }, + {NITF_BCS_A, 7, "Patch Start Line", "LNSTRT" }, + {NITF_BCS_A, 7, "Patch End Line", "LNSTOP" }, + {NITF_BCS_A, 5, "Number of Azimuth Lines", "AZL" }, + {NITF_BCS_A, 5, "Number of Valid Azimuth Lines", "NVL" }, + {NITF_BCS_A, 3, "First Valid Line", "FVL" }, + {NITF_BCS_A, 5, "Number of Pixels per Line", "NPIXEL" }, + {NITF_BCS_A, 5, "First Valid Pixel Index", "FVPIX" }, + {NITF_BCS_A, 3, "Spot Frame Number", "FRAME" }, + {NITF_BCS_A, 8, "GMT", "GMT" }, + {NITF_BCS_A, 7, "Scene Heading", "SHEAD" }, + {NITF_BCS_A, 6, "Ground Sweep Angle", "GSWEEP" }, + {NITF_BCS_A, 8, "Patch Shear Factor", "SHEAR" }, + {NITF_END, 0, NULL, NULL} +}; + +static nitf_TREDescription descrip_00115[] = { + {NITF_BCS_A, 4, "Patch Number", "PAT_NO" }, + {NITF_BCS_A, 1, "Last Patch of Search Scene", "LAST_PAT_FLAG" }, + {NITF_BCS_A, 7, "Patch Start Line", "LNSTRT" }, + {NITF_BCS_A, 7, "Patch End Line", "LNSTOP" }, + {NITF_BCS_A, 5, "Number of Azimuth Lines", "AZL" }, + {NITF_BCS_A, 5, "Number of Valid Azimuth Lines", "NVL" }, + {NITF_BCS_A, 3, "First Valid Line", "FVL" }, + {NITF_BCS_A, 5, "Number of Pixels per Line", "NPIXEL" }, + {NITF_BCS_A, 5, "First Valid Pixel Index", "FVPIX" }, + {NITF_BCS_A, 3, "Spot Frame Number", "FRAME" }, + {NITF_BCS_A, 8, "UTC", "UTC" }, + {NITF_BCS_A, 7, "Scene Heading", "SHEAD" }, + {NITF_BCS_A, 7, "Local Gravity", "GRAVITY" }, + {NITF_BCS_A, 5, "Ins Platform Velocity, North", "INS_V_NC" }, + {NITF_BCS_A, 5, "Ins Platform Velocity, East", "INS_V_EC" }, + {NITF_BCS_A, 5, "Ins Platform Velocity, Down", "INS_V_DC" }, + {NITF_BCS_A, 8, "Geodetic Latitude Offset", "OFFLAT" }, + {NITF_BCS_A, 8, "Geodetic Longitude Offset", "OFFLONG" }, + {NITF_BCS_A, 3, "Track Heading", "TRACK" }, + {NITF_BCS_A, 6, "Ground Sweep Angle", "GSWEEP" }, + {NITF_BCS_A, 8, "Patch Shear Factor", "SHEAR" }, + {NITF_END, 0, NULL, NULL} +}; + +/* Define the available descriptions and the default one */ +static nitf_TREDescriptionInfo descriptions[] = { + { "PATCHA_115", descrip_00115, 115 }, + { "PATCHA_74", descrip_00074, 74 }, + { NULL, NULL, NITF_TRE_DESC_NO_LENGTH } +}; + +static nitf_TREDescriptionSet descriptionSet = { 0, descriptions }; + +NITF_DECLARE_PLUGIN(PATCHA) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/PATCHB.c b/modules/c/nitf/shared/PATCHB.c new file mode 100644 index 000000000..8af33954b --- /dev/null +++ b/modules/c/nitf/shared/PATCHB.c @@ -0,0 +1,57 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + + {NITF_BCS_A, 4, "Patch Number", "PAT_NO" }, + {NITF_BCS_A, 1, "Last Patch of Search Scene", "LAST_PAT_FLAG" }, + {NITF_BCS_A, 7, "Patch Start Line", "LNSTRT" }, + {NITF_BCS_A, 7, "Patch End Line", "LNSTOP" }, + {NITF_BCS_A, 5, "Number of Azimuth Lines", "AZL" }, + {NITF_BCS_A, 5, "Number of Valid Azimuth Lines", "NVL" }, + {NITF_BCS_A, 3, "First Valid Line", "FVL" }, + {NITF_BCS_A, 5, "Number of Pixels per Line", "NPIXEL" }, + {NITF_BCS_A, 5, "First Valid Pixel Index", "FVPIX" }, + {NITF_BCS_A, 3, "Spot Frame Number", "FRAME" }, + {NITF_BCS_A, 8, "Coordinated Universal Time", "UTC" }, + {NITF_BCS_A, 7, "Scene Heading", "SHEAD" }, + {NITF_BCS_A, 7, "Local Gravity", "GRAVITY" }, + {NITF_BCS_A, 5, "Ins Platform Velocity, North", "INS_V_NC" }, + {NITF_BCS_A, 5, "Ins Platform Velocity, East", "INS_V_EC" }, + {NITF_BCS_A, 5, "Ins Platform Velocity, Down", "INS_V_DC" }, + {NITF_BCS_A, 8, "Geodetic Latitude Offset", "OFFLAT" }, + {NITF_BCS_A, 8, "Geodetic Longitude Offset", "OFFLONG" }, + {NITF_BCS_A, 3, "Track Heading", "TRACK" }, + {NITF_BCS_A, 6, "Ground Sweep Angle", "GSWEEP" }, + {NITF_BCS_A, 8, "Patch Shear Factor", "SHEAR" }, + {NITF_BCS_A, 6, "Batch Number", "BATCH_NO" }, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(PATCHB, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/PIAEQA.c b/modules/c/nitf/shared/PIAEQA.c new file mode 100644 index 000000000..893d19280 --- /dev/null +++ b/modules/c/nitf/shared/PIAEQA.c @@ -0,0 +1,42 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_A, 7, "Equipment Code", "EQPCODE" }, + {NITF_BCS_A, 45, "Equipment Nomenclature", "EQPNOMEN" }, + {NITF_BCS_A, 64, "Equipment Manufacturer", "EQPMAN" }, + {NITF_BCS_A, 1, "OB Type", "OBTYPE" }, + {NITF_BCS_A, 3, "Type Order of Battle", "ORDBAT" }, + {NITF_BCS_A, 2, "Country Produced", "CTRYPROD" }, + {NITF_BCS_A, 2, "Country Code Designed", "CTRYDSN" }, + {NITF_BCS_A, 6, "Object View", "OBJVIEW" }, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(PIAEQA, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/PIAEVA.c b/modules/c/nitf/shared/PIAEVA.c new file mode 100644 index 000000000..8dcdc1d7d --- /dev/null +++ b/modules/c/nitf/shared/PIAEVA.c @@ -0,0 +1,36 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_A, 38, "Event Name", "EVENTNAME" }, + {NITF_BCS_A, 8, "Event Type", "EVENTTYPE" }, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(PIAEVA, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/PIAIMB.c b/modules/c/nitf/shared/PIAIMB.c new file mode 100644 index 000000000..38ef94e1c --- /dev/null +++ b/modules/c/nitf/shared/PIAIMB.c @@ -0,0 +1,47 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_A, 3, "Cloud Cover", "cloud" }, + {NITF_BCS_A, 1, "Standard Radiometric?", "stdrd" }, + {NITF_BCS_A, 12, "Sensor Mode", "smode" }, + {NITF_BCS_A, 18, "Sensor Name", "sname" }, + {NITF_BCS_A, 255, "Source", "srce" }, + {NITF_BCS_A, 2, "Compression Generation", "cmgen" }, + {NITF_BCS_A, 1, "Subjective Quality", "squal" }, + {NITF_BCS_A, 7, "PIA Mission Number", "misnm" }, + {NITF_BCS_A, 32, "Camera Specs", "cspec" }, + {NITF_BCS_A, 2, "Project ID Code", "pjtid" }, + {NITF_BCS_A, 1, "Generation", "gener" }, + {NITF_BCS_A, 1, "Exploitation Support", "expls" }, + {NITF_BCS_A, 2, "Other Conditions", "othrc" }, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(PIAIMB, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/PIAIMC.c b/modules/c/nitf/shared/PIAIMC.c new file mode 100644 index 000000000..faa69ccf0 --- /dev/null +++ b/modules/c/nitf/shared/PIAIMC.c @@ -0,0 +1,53 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_N, 3, "Cloud Cover", "CLOUDCVR" }, + {NITF_BCS_A, 1, "Standard Radiometric Product", "SRP" }, + {NITF_BCS_A, 12, "Sensor Mode", "SENSMODE" }, + {NITF_BCS_A, 18, "Sensor Name", "SENSNAME" }, + {NITF_BCS_A, 255, "Source", "SOURCE" }, + {NITF_BCS_N, 2, "Compression Generation", "COMGEN" }, + {NITF_BCS_A, 1, "Subjective Quality", "SUBQUAL" }, + {NITF_BCS_A, 7, "PIA Mission Number", "PIAMSNNUM" }, + {NITF_BCS_A, 32, "Camera Specs", "CAMSPECS" }, + {NITF_BCS_A, 2, "Project ID Code", "PROJID" }, + {NITF_BCS_N, 1, "Generation", "GENERATION" }, + {NITF_BCS_A, 1, "Exploitation Support Data", "ESD" }, + {NITF_BCS_A, 2, "Other Conditions", "OTHERCOND" }, + {NITF_BCS_N, 7, "Mean GSD", "MEANGSD" }, + {NITF_BCS_A, 3, "Image Datum", "IDATUM" }, + {NITF_BCS_A, 3, "Image Ellipsoid", "IELLIP" }, + {NITF_BCS_A, 2, "Image Processing Level", "PREPROC" }, + {NITF_BCS_A, 2, "Image Projection System", "IPROJ" }, + {NITF_BCS_N, 8, "Satellite Track", "SATTRACK" }, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(PIAIMC, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/PIAPEA.c b/modules/c/nitf/shared/PIAPEA.c new file mode 100644 index 000000000..62326f26a --- /dev/null +++ b/modules/c/nitf/shared/PIAPEA.c @@ -0,0 +1,38 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_A, 28, "Last Name", "LASTNME" }, + {NITF_BCS_A, 28, "First Name", "FIRSTNME" }, + {NITF_BCS_A, 28, "Middle Name", "MIDNME" }, + {NITF_BCS_A, 6, "Birth Date", "DOB" }, + {NITF_BCS_A, 2, "Associated Country", "ASSOCTRY" }, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(PIAPEA, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/PIAPEB.c b/modules/c/nitf/shared/PIAPEB.c new file mode 100644 index 000000000..9e1650516 --- /dev/null +++ b/modules/c/nitf/shared/PIAPEB.c @@ -0,0 +1,39 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_A, 28, "Last Name", "LASTNME" }, + {NITF_BCS_A, 28, "First Name", "FIRSTNME" }, + {NITF_BCS_A, 28, "Middle Name", "MIDNME" }, + {NITF_BCS_A, 8, "Birth Date", "DOB" }, + {NITF_BCS_A, 2, "Associated Country", "ASSOCTRY" }, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(PIAPEB, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/PIAPRC.c b/modules/c/nitf/shared/PIAPRC.c new file mode 100644 index 000000000..3c8d9d7c5 --- /dev/null +++ b/modules/c/nitf/shared/PIAPRC.c @@ -0,0 +1,81 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_A, 64, "Access ID", "accid" }, + {NITF_BCS_A, 32, "FM Control Number", "fmctl" }, + {NITF_BCS_A, 1, "Subjective Detail", "sdet" }, + {NITF_BCS_A, 2, "Product Code", "pcode" }, + {NITF_BCS_A, 6, "Producer Subelement", "psube" }, + {NITF_BCS_A, 20, "Product ID Number", "pidnm" }, + {NITF_BCS_A, 10, "Product Short Name", "pname" }, + {NITF_BCS_A, 2, "Producer Code", "maker" }, + {NITF_BCS_A, 14, "Product Create Time", "ctime" }, + {NITF_BCS_A, 40, "Map ID", "mapid" }, + {NITF_BCS_N, 2, "SECTITLE Repetitions", "strep" }, + + {NITF_LOOP, 0, NULL, "strep"}, + + {NITF_BCS_A, 48, "SECTITLE", "SECTITLE" }, + + {NITF_ENDLOOP, 0, NULL, NULL}, + + {NITF_BCS_N, 2, "REQORG Repetitions", "rorep" }, + {NITF_LOOP, 0, NULL, "rorep" }, + {NITF_BCS_A, 64, "Requesting Organization", "REQORG" }, + + {NITF_ENDLOOP, 0, NULL, NULL}, + + {NITF_BCS_N, 2, "KEYWORD Repetitions", "kwrep" }, + {NITF_LOOP, 0, NULL, "kwrep"}, + + {NITF_BCS_A, 255, "KEYWORD", "KEYWORD" }, + + {NITF_ENDLOOP, 0, NULL, NULL}, + + {NITF_BCS_N, 2, "ASSRPT Repetitions", "arrep" }, + + {NITF_LOOP, 0, NULL, "arrep"}, + + {NITF_BCS_A, 20, "ASSRPT", "ASSRPT" }, + + {NITF_ENDLOOP, 0, NULL, NULL}, + + {NITF_BCS_N, 2, "ATEXT Repetitions", "atrep" }, + + {NITF_LOOP, 0, NULL, "atrep" }, + + {NITF_BCS_A, 255, "ATEXT", "ATEXT" }, + + {NITF_ENDLOOP, 0, NULL, NULL}, + + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(PIAPRC, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/PIAPRD.c b/modules/c/nitf/shared/PIAPRD.c new file mode 100644 index 000000000..5ce3983fc --- /dev/null +++ b/modules/c/nitf/shared/PIAPRD.c @@ -0,0 +1,66 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_A, 64, "Access ID", "ACCESSID" }, + {NITF_BCS_A, 32, "FM Control Number", "FMCNTROL" }, + {NITF_BCS_A, 1, "Subjective Detail", "SUBDET" }, + {NITF_BCS_A, 2, "Product Code", "PRODCODE" }, + {NITF_BCS_A, 6, "Producer Subelement", "PRODCRSE" }, + {NITF_BCS_A, 20, "Product ID Number", "PRODIDNO" }, + {NITF_BCS_A, 10, "Product Short Name", "PRODSNME" }, + {NITF_BCS_A, 2, "Producer Code", "PRODCRCD" }, + {NITF_BCS_A, 14, "Product Create Time", "PRODCRTM" }, + {NITF_BCS_A, 40, "Map ID", "MAPID" }, + {NITF_BCS_N, 2, "SECTITLE Repetitions", "SECTTREP" }, + {NITF_LOOP, 0, NULL, "SECTTREP"}, + {NITF_BCS_A, 40, "Section Title", "SECTITLE" }, + {NITF_BCS_A, 5, "Page/Part Number", "PPNUM" }, + {NITF_BCS_N, 3, "Total Pages/Parts", "TPP" }, + {NITF_ENDLOOP, 0, NULL, NULL}, + {NITF_BCS_N, 2, "REQORG Repetitions", "RQORGREP" }, + {NITF_LOOP, 0, NULL, "RQORGREP"}, + {NITF_BCS_A, 64, "Requesting Organization", "REQORG" }, + {NITF_ENDLOOP, 0, NULL, NULL}, + {NITF_BCS_N, 2, "Keyword Repetitions", "KEYWDREP" }, + {NITF_LOOP, 0, NULL, "KEYWDREP"}, + {NITF_BCS_A, 255, "Keyword", "KEYWORD" }, + {NITF_ENDLOOP, 0, NULL, NULL}, + {NITF_BCS_N, 2, "ASSRPT Repetitions", "ASRPTREP" }, + {NITF_LOOP, 0, NULL, "ASRPTREP"}, + {NITF_BCS_A, 20, "Associated Report", "ASSRPT" }, + {NITF_ENDLOOP, 0, NULL, NULL}, + {NITF_BCS_N, 2, "Assoc. Text Repetitions", "ATEXTREP" }, + {NITF_LOOP, 0, NULL, "ATEXTREP"}, + {NITF_BCS_A, 255, "Associated Text", "ATEXT" }, + {NITF_ENDLOOP, 0, NULL, NULL}, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(PIAPRD, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/PIATGA.c b/modules/c/nitf/shared/PIATGA.c new file mode 100644 index 000000000..a34b13948 --- /dev/null +++ b/modules/c/nitf/shared/PIATGA.c @@ -0,0 +1,41 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_A, 15, "Target UTM", "TGTUTM" }, + {NITF_BCS_A, 15, "Target ID", "PIATGAID" }, + {NITF_BCS_A, 2, "Country Code", "PIACTRY" }, + {NITF_BCS_A, 5, "Category Code", "PIACAT" }, + {NITF_BCS_A, 15, "Target Geographic Coordinates", "TGTGEO" }, + {NITF_BCS_A, 3, "Target Coordinate Datum", "DATUM" }, + {NITF_BCS_A, 38, "Target Name", "TGTNAME" }, + {NITF_BCS_N, 3, "Percent Coverage", "PERCOVER" }, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(PIATGA, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/PIATGB.c b/modules/c/nitf/shared/PIATGB.c new file mode 100644 index 000000000..aa64ce06f --- /dev/null +++ b/modules/c/nitf/shared/PIATGB.c @@ -0,0 +1,43 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_A, 15, "Target UTM", "TGTUTM" }, + {NITF_BCS_A, 15, "Target Identification", "PIATGAID" }, + {NITF_BCS_A, 2, "Country Code", "PIACTRY" }, + {NITF_BCS_A, 5, "Category Code", "PIACAT" }, + {NITF_BCS_A, 15, "Target Geographic Coordinates", "TGTGEO" }, + {NITF_BCS_A, 3, "Target Coordinate Datum", "DATUM" }, + {NITF_BCS_A, 38, "Target Name", "TGTNAME" }, + {NITF_BCS_N, 3, "Percent Coverage", "PERCOVER" }, + {NITF_BCS_A, 10, "Target Latitude", "TGTLAT" }, + {NITF_BCS_A, 11, "Target Longitude", "TGTLON" }, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(PIATGB, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/PIXQLA.c b/modules/c/nitf/shared/PIXQLA.c new file mode 100644 index 000000000..451474866 --- /dev/null +++ b/modules/c/nitf/shared/PIXQLA.c @@ -0,0 +1,44 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_A, 3, "Number of Associated Image Segments", "NUMAIS", }, + {NITF_IF, 0, "ne ALL", "NUMAIS"}, + {NITF_LOOP, 0, NULL, "NUMAIS"}, + {NITF_BCS_N, 3, "Associated Image Segment Display Level", "AISDLVL" }, + {NITF_ENDLOOP, 0, NULL, NULL}, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_BCS_N, 4, "Number of Pixel Quality Conditions", "NPIXQUAL", }, + {NITF_BCS_A, 1, "Pixel Quality Bit Value", "PQ_BIT_VALUE", }, + {NITF_LOOP, 0, NULL, "NPIXQUAL"}, + {NITF_BCS_A, 40, "Pixel Quality Condition", "PQ_CONDITION" }, + {NITF_ENDLOOP, 0, NULL, NULL}, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(PIXQLA, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/PLTFMA.c b/modules/c/nitf/shared/PLTFMA.c new file mode 100644 index 000000000..16d2ad11d --- /dev/null +++ b/modules/c/nitf/shared/PLTFMA.c @@ -0,0 +1,81 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_N, 4, "VERNUM", "VERNUM" }, + {NITF_BCS_A, 12, "P_NAME", "P_NAME" }, + {NITF_BCS_A, 40, "P_DESCR", "P_DESCR" }, + {NITF_BCS_A, 8, "P_DATE", "P_DATE" }, + {NITF_BCS_A, 9, "P_TIME", "P_TIME" }, + {NITF_BCS_A, 1, "P_TYPE", "P_TYPE" }, + {NITF_IF, 0, "eq G", "P_TYPE"}, + {NITF_BCS_A, 3, "SNSR_HT", "SNSR_HT" }, + {NITF_BCS_A, 21, "SNSRLOC", "SNSRLOC" }, + {NITF_BCS_A, 3, "SNSRHDNG", "SNSRHDNG" }, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq T", "P_TYPE"}, + {NITF_BCS_A, 3, "SNSR_HT", "SNSR_HT" }, + {NITF_BCS_A, 21, "SNSRLOC", "SNSRLOC" }, + {NITF_BCS_A, 3, "SNSRHDNG", "SNSRHDNG" }, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq M", "P_TYPE"}, + {NITF_BCS_A, 3, "SNSR_HT", "SNSR_HT" }, + {NITF_BCS_A, 21, "SNSRLOC", "SNSRLOC" }, + {NITF_BCS_A, 3, "SNSRHDNG", "SNSRHDNG" }, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq A", "P_TYPE"}, + {NITF_BCS_A, 15, "AC_TYPE", "AC_TYPE" }, + {NITF_BCS_A, 12, "AC_SERIAL", "AC_SERIAL" }, + {NITF_BCS_A, 10, "AC_T_NUM", "AC_T_NUM" }, + {NITF_BCS_A, 5, "AC_PITCH", "AC_PITCH" }, + {NITF_BCS_A, 5, "AC_ROLL", "AC_ROLL" }, + {NITF_BCS_A, 3, "AC_HDNG", "AC_HDNG" }, + {NITF_BCS_A, 1, "AC_REF_PT", "AC_REF_PT" }, + {NITF_BCS_A, 9, "AC_POS_X", "AC_POS_X" }, + {NITF_BCS_A, 9, "AC_POS_Y", "AC_POS_Y" }, + {NITF_BCS_A, 9, "AC_POS_Z", "AC_POS_Z" }, + {NITF_BCS_A, 9, "AC_VEL_X", "AC_VEL_X" }, + {NITF_BCS_A, 9, "AC_VEL_Y", "AC_VEL_Y" }, + {NITF_BCS_A, 9, "AC_VEL_Z", "AC_POS_Z" }, + {NITF_BCS_A, 8, "AC_ACC_X", "AC_ACC_X" }, + {NITF_BCS_A, 8, "AC_ACC_Y", "AC_ACC_Y" }, + {NITF_BCS_A, 8, "AC_ACC_Z", "AC_POS_Z" }, + {NITF_BCS_A, 5, "AC_SPEED", "AC_SPEED" }, + {NITF_BCS_A, 21, "ENTLOC", "ENTLOC" }, + {NITF_BCS_A, 6, "ENTALT", "ENTALT" }, + {NITF_BCS_A, 21, "EXITLOC", "EXITLOC" }, + {NITF_BCS_A, 6, "EXITALT", "EXITALTH" }, + {NITF_BCS_A, 5, "INS_V_NC", "INS_V_NC" }, + {NITF_BCS_A, 5, "INS_V_EC", "INS_V_EC" }, + {NITF_BCS_A, 5, "INS_V_DC", "INS_V_DC" }, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(PLTFMA, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/PRJPSB.c b/modules/c/nitf/shared/PRJPSB.c new file mode 100644 index 000000000..d2f6e5d75 --- /dev/null +++ b/modules/c/nitf/shared/PRJPSB.c @@ -0,0 +1,41 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_A, 80, "Projection Name", "PRN" }, + {NITF_BCS_A, 2, "Projection Code", "PCO" }, + {NITF_BCS_N, 1, "Number of Projection Parameters", "NUMPRJ" }, + {NITF_LOOP, 0, NULL, "NUMPRJ"}, + {NITF_BCS_N, 15, "Projection Parameter", "PRJ" }, + {NITF_ENDLOOP, 0, NULL, NULL}, + {NITF_BCS_N, 15, "Projection False X (Easting) Origin", "XOR" }, + {NITF_BCS_N, 15, "Projection False Y (Northing) Origin" "YOR" }, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(PRJPSB, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/REGPTB.c b/modules/c/nitf/shared/REGPTB.c new file mode 100644 index 000000000..9cd1e258a --- /dev/null +++ b/modules/c/nitf/shared/REGPTB.c @@ -0,0 +1,43 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_N, 4, "Number of Registration Points to Follow", + "NUMPTS" }, + {NITF_LOOP, 0, NULL, "NUMPTS"}, + {NITF_BCS_A, 10, "Registration Point ID", "PID" }, + {NITF_BCS_N, 15, "Longitude/Easting", "LON" }, + {NITF_BCS_N, 15, "Latitude/Northing", "LAT" }, + {NITF_BCS_N, 15, "Elevation", "ZVL" }, + {NITF_BCS_N, 11, "Column Number of Registration Point", "DIX" }, + {NITF_BCS_N, 11, "Row Number of Registration Point", "DIY" }, + {NITF_ENDLOOP, 0, NULL, NULL}, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(REGPTB, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/RPC00B.c b/modules/c/nitf/shared/RPC00B.c new file mode 100644 index 000000000..69684e1f2 --- /dev/null +++ b/modules/c/nitf/shared/RPC00B.c @@ -0,0 +1,59 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_N, 1, "Success", "SUCCESS" }, + {NITF_BCS_A, 7, "Error - Bias", "ERR_BIAS" }, + {NITF_BCS_A, 7, "Error - Random", "ERR_RAND" }, + {NITF_BCS_N, 6, "Line Offset", "LINE_OFF" }, + {NITF_BCS_N, 5, "Sample Offset", "SAMP_OFF" }, + {NITF_BCS_A, 8, "Geodetic Latitude Offset", "LAT_OFF" }, + {NITF_BCS_A, 9, "Geodetic Longitude Offset", "LONG_OFF" }, + {NITF_BCS_N, 5, "Geodetic Height Offset", "HEIGHT_OFF" }, + {NITF_BCS_N, 6, "Line Scale", "LINE_SCALE" }, + {NITF_BCS_N, 5, "Sample Scale", "SAMP_SCALE" }, + {NITF_BCS_A, 8, "Geodetic Latitude Scale", "LAT_SCALE" }, + {NITF_BCS_A, 9, "Geodetic Longitude Scale", "LONG_SCALE" }, + {NITF_BCS_N, 5, "Geodetic Height Scale", "HEIGHT_SCALE" }, + {NITF_LOOP, 0, NITF_CONST_N, "20"}, + {NITF_BCS_A, 12, "Line Numerator Coefficient", + "LINE_NUM_COEFF" }, + {NITF_ENDLOOP, 0, NULL, NULL}, + {NITF_LOOP, 0, NITF_CONST_N, "20"}, + {NITF_BCS_A, 12, "Line Denominator Coefficient", "LINE_DEN_COEFF" }, + {NITF_ENDLOOP, 0, NULL, NULL}, + {NITF_LOOP, 0, NITF_CONST_N, "20"}, + {NITF_BCS_A, 12, "Sample Numerator Coefficient", "SAMP_NUM_COEFF" }, + {NITF_ENDLOOP, 0, NULL, NULL}, + {NITF_LOOP, 0, NITF_CONST_N, "20"}, + {NITF_BCS_A, 12, "Sample Denominator Coefficient", "SAMP_DEN_COEFF" }, + {NITF_ENDLOOP, 0, NULL, NULL}, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(RPC00B, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/RPFDES.c b/modules/c/nitf/shared/RPFDES.c new file mode 100644 index 000000000..d4d47ec2f --- /dev/null +++ b/modules/c/nitf/shared/RPFDES.c @@ -0,0 +1,47 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BINARY, 1, "location section length", "LOCLEN" }, + {NITF_IF, 0, "> 0", "LOCLEN"}, + {NITF_BINARY, 1, "component location table offset", "CLTOFF" }, + {NITF_BINARY, 1, "# of section location records", "SECRECS" }, + {NITF_BINARY, 1, "location record length", "RECLEN" }, + {NITF_BINARY, 1, "component aggregate length", "AGGLEN" }, + {NITF_LOOP, 0, NULL, "SECRECS"}, + {NITF_BINARY, 1, "location ID code", "LOCID" }, + {NITF_BINARY, 1, "location section length", "SECLEN" }, + {NITF_BINARY, 1, "physical index", "PHYSIDX" }, + {NITF_ENDLOOP, 0, NULL, NULL}, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_BINARY, NITF_TRE_GOBBLE, "unknown", "UNKNOWN" }, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(RPFDES, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/RPFHDR.c b/modules/c/nitf/shared/RPFHDR.c new file mode 100644 index 000000000..6d2938f83 --- /dev/null +++ b/modules/c/nitf/shared/RPFHDR.c @@ -0,0 +1,44 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BINARY, 1, "endian flag", "ENDIAN" }, + {NITF_BINARY, 2, "header section length", "HDSECL" }, + {NITF_BCS_A, 12, "filename", "FILENM" }, + {NITF_BINARY, 1, "new flag", "NEWFLG" }, + {NITF_BCS_A, 15, "standard number", "STDNUM" }, + {NITF_BCS_A, 8, "standard date", "STDDAT" }, + {NITF_BCS_A, 1, "classification", "CLASS" }, + {NITF_BCS_A, 2, "country code", "COUNTR" }, + {NITF_BCS_A, 2, "release", "RELEAS" }, + {NITF_BINARY, 4, "location sect phys loc", "LOCSEC" }, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(RPFHDR, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/RPFIMG.c b/modules/c/nitf/shared/RPFIMG.c new file mode 100644 index 000000000..3d15ea586 --- /dev/null +++ b/modules/c/nitf/shared/RPFIMG.c @@ -0,0 +1,45 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BINARY, 1, "location section length", "LOCLEN" }, + {NITF_BINARY, 1, "component location table offset", "CLTOFF" }, + {NITF_BINARY, 1, "# of section location records", "SECRECS" }, + {NITF_BINARY, 1, "location record length", "RECLEN" }, + {NITF_BINARY, 1, "component aggregate length", "AGGLEN" }, + {NITF_LOOP, 0, NULL, "SECRECS"}, + {NITF_BINARY, 1, "location ID code", "LOCID" }, + {NITF_BINARY, 1, "location section length", "SECLEN" }, + {NITF_BINARY, 1, "physical index", "PHYSIDX" }, + {NITF_ENDLOOP, 0, NULL, NULL}, + {NITF_BINARY, NITF_TRE_GOBBLE, "unknown", "UNKNOWN" }, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(RPFIMG, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/RSMAPA.c b/modules/c/nitf/shared/RSMAPA.c new file mode 100644 index 000000000..64fc94b82 --- /dev/null +++ b/modules/c/nitf/shared/RSMAPA.c @@ -0,0 +1,122 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_A, 80, "Image Identifier", "IID" }, + {NITF_BCS_A, 40, "RSM Image Support Data Edition", "EDITION" }, + {NITF_BCS_A, 40, "Triangulation ID", "TID" }, + + {NITF_BCS_N, 2, "Number of Parameters", "NPAR" }, + + {NITF_BCS_A, 21, "Local Coord Origin (XUOL)", "XUOL" }, + {NITF_BCS_A, 21, "Local Coord Origin (YUOL)", "YUOL" }, + {NITF_BCS_A, 21, "Local Coord Origin (ZUOL)", "ZUOL" }, + + {NITF_BCS_A, 21, "Local Coord Unit Vector (XUXL)", "XUXL" }, + {NITF_BCS_A, 21, "Local Coord Unit Vector (XUYL)", "XUYL" }, + {NITF_BCS_A, 21, "Local Coord Unit Vector (XUZL)", "XUZL" }, + + {NITF_BCS_A, 21, "Local Coord Unit Vector (YUXL)", "YUXL" }, + {NITF_BCS_A, 21, "Local Coord Unit Vector (YUYL)", "YUYL" }, + {NITF_BCS_A, 21, "Local Coord Unit Vector (YUZL)", "YUZL" }, + + {NITF_BCS_A, 21, "Local Coord Unit Vector (ZUXL)", "ZUXL" }, + {NITF_BCS_A, 21, "Local Coord Unit Vector (ZUYL)", "ZUYL" }, + {NITF_BCS_A, 21, "Local Coord Unit Vector (ZUZL)", "ZUZL" }, + + {NITF_BCS_A, 2, "Image Row Constant Index", "IR0" }, + {NITF_BCS_A, 2, "Image Row X Index", "IRX" }, + {NITF_BCS_A, 2, "Image Row Y Index", "IRY" }, + {NITF_BCS_A, 2, "Image Row Z Index", "IRZ" }, + + {NITF_BCS_A, 2, "Image Row X^2 Index", "IRXX" }, + {NITF_BCS_A, 2, "Image Row XY Index", "IRXY" }, + {NITF_BCS_A, 2, "Image Row XZ Index", "IRXZ" }, + + + {NITF_BCS_A, 2, "Image Row Y^2 Index", "IRYY" }, + {NITF_BCS_A, 2, "Image Row YZ Index", "IRYZ" }, + + {NITF_BCS_A, 2, "Image Row Z^2 Index", "IRZZ" }, + + + + {NITF_BCS_A, 2, "Image Col Constant Index", "IC0" }, + {NITF_BCS_A, 2, "Image Col X Index", "ICX" }, + {NITF_BCS_A, 2, "Image Col Y Index", "ICY" }, + {NITF_BCS_A, 2, "Image Col Z Index", "ICZ" }, + + {NITF_BCS_A, 2, "Image Col X^2 Index", "ICXX" }, + {NITF_BCS_A, 2, "Image Col XY Index", "ICXY" }, + {NITF_BCS_A, 2, "Image Col XZ Index", "ICXZ" }, + + + {NITF_BCS_A, 2, "Image Col Y^2 Index", "ICYY" }, + {NITF_BCS_A, 2, "Image Col YZ Index", "ICYZ" }, + + {NITF_BCS_A, 2, "Image Col Z^2 Index", "ICZZ" }, + + {NITF_BCS_A, 2, "Ground X Constant Index", "GX0" }, + {NITF_BCS_A, 2, "Ground Y Constant Index", "GY0" }, + {NITF_BCS_A, 2, "Ground Z Constant Index", "GZ0" }, + + {NITF_BCS_A, 2, "Ground Rotation X", "GXR" }, + {NITF_BCS_A, 2, "Ground Rotation Y", "GYR" }, + {NITF_BCS_A, 2, "Ground Rotation Z", "GZR" }, + + {NITF_BCS_A, 2, "Ground Scale", "GS" }, + + {NITF_BCS_A, 2, "Ground X Adj Proportional to X index", "GXX" }, + {NITF_BCS_A, 2, "Ground X Adj Proportional to Y index", "GXY" }, + {NITF_BCS_A, 2, "Ground X Adj Proportional to Z index", "GXZ" }, + + + {NITF_BCS_A, 2, "Ground Y Adj Proportional to X index", "GYX" }, + {NITF_BCS_A, 2, "Ground Y Adj Proportional to Y index", "GYY" }, + {NITF_BCS_A, 2, "Ground Y Adj Proportional to Z index", "GYZ" }, + + {NITF_BCS_A, 2, "Ground Z Adj Proportional to X index", "GZX" }, + {NITF_BCS_A, 2, "Ground Z Adj Proportional to Y index", "GZY" }, + {NITF_BCS_A, 2, "Ground Z Adj Proportional to Z index", "GZZ" }, + + + {NITF_LOOP, 0, NULL, "NPAR" }, + + {NITF_BCS_A, 21, "Component Value", "PARVAL" }, + + {NITF_ENDLOOP, 0, NULL, NULL}, + + + {NITF_END, 0, NULL, NULL} + + +}; + + + +NITF_DECLARE_SINGLE_PLUGIN(RSMAPA, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/RSMDCA.c b/modules/c/nitf/shared/RSMDCA.c new file mode 100644 index 000000000..2f748fc65 --- /dev/null +++ b/modules/c/nitf/shared/RSMDCA.c @@ -0,0 +1,141 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + +NITF_CXX_GUARD + +static int count(nitf_TRE* tre, char idx[10][10], int depth, nitf_Error* error) +{ + int npart; + nitf_Field* field = nitf_TRE_getField(tre, "NPART"); + nitf_Field_get(field, &npart, NITF_CONV_INT, sizeof(npart), error); + return ( ((npart + 1) * npart) / 2 ); + +} + +static nitf_TREDescription description[] = { + {NITF_BCS_A, 80, "Image Identifier", "IID" }, + {NITF_BCS_A, 40, "RSM Image Support Data Edition", "EDITION" }, + {NITF_BCS_A, 40, "Triangulation ID", "TID" }, + + {NITF_BCS_N, 2, "Number of Parameters", "NPAR" }, + {NITF_BCS_N, 3, "Number of Images", "NIMGE" }, + + {NITF_BCS_N, 5, "Total Number of Parameters", "NPART" }, + + {NITF_LOOP, 0, NULL, "NIMGE"}, + + {NITF_BCS_A, 80, "Image Identifier", "IIDI" }, + {NITF_BCS_N, 2, "Number of Parameters", "NPARI" }, + + {NITF_ENDLOOP, 0, NULL, NULL}, + + {NITF_BCS_A, 21, "Local Coord Origin (XUOL)", "XUOL" }, + {NITF_BCS_A, 21, "Local Coord Origin (YUOL)", "YUOL" }, + {NITF_BCS_A, 21, "Local Coord Origin (ZUOL)", "ZUOL" }, + + {NITF_BCS_A, 21, "Local Coord Unit Vector (XUXL)", "XUXL" }, + {NITF_BCS_A, 21, "Local Coord Unit Vector (XUYL)", "XUYL" }, + {NITF_BCS_A, 21, "Local Coord Unit Vector (XUZL)", "XUZL" }, + + {NITF_BCS_A, 21, "Local Coord Unit Vector (YUXL)", "YUXL" }, + {NITF_BCS_A, 21, "Local Coord Unit Vector (YUYL)", "YUYL" }, + {NITF_BCS_A, 21, "Local Coord Unit Vector (YUZL)", "YUZL" }, + + {NITF_BCS_A, 21, "Local Coord Unit Vector (ZUXL)", "ZUXL" }, + {NITF_BCS_A, 21, "Local Coord Unit Vector (ZUYL)", "ZUYL" }, + {NITF_BCS_A, 21, "Local Coord Unit Vector (ZUZL)", "ZUZL" }, + + {NITF_BCS_A, 2, "Image Row Constant Index", "IR0" }, + {NITF_BCS_A, 2, "Image Row X Index", "IRX" }, + {NITF_BCS_A, 2, "Image Row Y Index", "IRY" }, + {NITF_BCS_A, 2, "Image Row Z Index", "IRZ" }, + + {NITF_BCS_A, 2, "Image Row X^2 Index", "IRXX" }, + {NITF_BCS_A, 2, "Image Row XY Index", "IRXY" }, + {NITF_BCS_A, 2, "Image Row XZ Index", "IRXZ" }, + + + {NITF_BCS_A, 2, "Image Row Y^2 Index", "IRYY" }, + {NITF_BCS_A, 2, "Image Row YZ Index", "IRYZ" }, + + {NITF_BCS_A, 2, "Image Row Z^2 Index", "IRZZ" }, + + + + {NITF_BCS_A, 2, "Image Col Constant Index", "IC0" }, + {NITF_BCS_A, 2, "Image Col X Index", "ICX" }, + {NITF_BCS_A, 2, "Image Col Y Index", "ICY" }, + {NITF_BCS_A, 2, "Image Col Z Index", "ICZ" }, + + {NITF_BCS_A, 2, "Image Col X^2 Index", "ICXX" }, + {NITF_BCS_A, 2, "Image Col XY Index", "ICXY" }, + {NITF_BCS_A, 2, "Image Col XZ Index", "ICXZ" }, + + + {NITF_BCS_A, 2, "Image Col Y^2 Index", "ICYY" }, + {NITF_BCS_A, 2, "Image Col YZ Index", "ICYZ" }, + + {NITF_BCS_A, 2, "Image Col Z^2 Index", "ICZZ" }, + + {NITF_BCS_A, 2, "Ground X Constant Index", "GX0" }, + {NITF_BCS_A, 2, "Ground Y Constant Index", "GY0" }, + {NITF_BCS_A, 2, "Ground Z Constant Index", "GZ0" }, + + {NITF_BCS_A, 2, "Ground Rotation X", "GXR" }, + {NITF_BCS_A, 2, "Ground Rotation Y", "GYR" }, + {NITF_BCS_A, 2, "Ground Rotation Z", "GZR" }, + + {NITF_BCS_A, 2, "Ground Scale", "GS" }, + + {NITF_BCS_A, 2, "Ground X Adj Proportional to X index", "GXX" }, + {NITF_BCS_A, 2, "Ground X Adj Proportional to Y index", "GXY" }, + {NITF_BCS_A, 2, "Ground X Adj Proportional to Z index", "GXZ" }, + + + {NITF_BCS_A, 2, "Ground Y Adj Proportional to X index", "GYX" }, + {NITF_BCS_A, 2, "Ground Y Adj Proportional to Y index", "GYY" }, + {NITF_BCS_A, 2, "Ground Y Adj Proportional to Z index", "GYZ" }, + + {NITF_BCS_A, 2, "Ground Z Adj Proportional to X index", "GZX" }, + {NITF_BCS_A, 2, "Ground Z Adj Proportional to Y index", "GZY" }, + {NITF_BCS_A, 2, "Ground Z Adj Proportional to Z index", "GZZ" }, + + + {NITF_LOOP, 0, NITF_FUNCTION, (char*)&count}, + + {NITF_BCS_A, 21, "Direct Error Covariance Element", "DERCOV" }, + + {NITF_ENDLOOP, 0, NULL, NULL}, + + + {NITF_END, 0, NULL, NULL} + + +}; + + + +NITF_DECLARE_SINGLE_PLUGIN(RSMDCA, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/RSMECA.c b/modules/c/nitf/shared/RSMECA.c new file mode 100644 index 000000000..7a0a27291 --- /dev/null +++ b/modules/c/nitf/shared/RSMECA.c @@ -0,0 +1,210 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + +NITF_CXX_GUARD + +static int numopg(nitf_TRE* tre, char idx[10][10], int depth, nitf_Error* error) +{ + nitf_Field* field; + int numopg, x; + char fname[64]; + strcpy(fname, "NUMOPG"); + x = strlen(idx[0]); + + strcat(fname, idx[0]); + + field = nitf_TRE_getField(tre, fname); + nitf_Field_get(field, &numopg, NITF_CONV_INT, sizeof(numopg), error); + return ( ((numopg + 1) * numopg) / 2 ); + +} + + +static int mapped(nitf_TRE* tre, char idx[10][10], int depth, nitf_Error* error) +{ + int npar, npar0; + nitf_Field* field = nitf_TRE_getField(tre, "NPAR"); + nitf_Field_get(field, &npar, NITF_CONV_INT, sizeof(npar), error); + + field = nitf_TRE_getField(tre, "NPAR0"); + nitf_Field_get(field, &npar0, NITF_CONV_INT, sizeof(npar0), error); + return ( npar * npar0 ); + +} + +static nitf_TREDescription description[] = { + {NITF_BCS_A, 80, "Image Identifier", "IID" }, + {NITF_BCS_A, 40, "RSM Image Support Data Edition", "EDITION" }, + {NITF_BCS_A, 40, "Triangulation ID", "TID" }, + + {NITF_BCS_A, 1, "Include Indirect Error Covariance", "INCLIC" }, + {NITF_BCS_A, 1, "Include Indirect Error Covariance", "INCLUC" }, + + /* {NITF_IF, 0, NITF_FUNCTION, &inclic }, */ + + {NITF_IF, 0, "eq Y", "INCLIC"}, + {NITF_BCS_N, 2, "Number of Parameters", "NPAR" }, + {NITF_BCS_N, 2, "Number of Original Adjustable Params", "NPAR0" }, + {NITF_BCS_N, 2, "Number of Independent Subgroups", "IGN" }, + + {NITF_BCS_A, 8, "Version Date of the Orig Image Err Cov", "CVDATE"}, + + + {NITF_BCS_A, 21, "Local Coord Origin (XUOL)", "XUOL" }, + {NITF_BCS_A, 21, "Local Coord Origin (YUOL)", "YUOL" }, + {NITF_BCS_A, 21, "Local Coord Origin (ZUOL)", "ZUOL" }, + + {NITF_BCS_A, 21, "Local Coord Unit Vector (XUXL)", "XUXL" }, + {NITF_BCS_A, 21, "Local Coord Unit Vector (XUYL)", "XUYL" }, + {NITF_BCS_A, 21, "Local Coord Unit Vector (XUZL)", "XUZL" }, + + {NITF_BCS_A, 21, "Local Coord Unit Vector (YUXL)", "YUXL" }, + {NITF_BCS_A, 21, "Local Coord Unit Vector (YUYL)", "YUYL" }, + {NITF_BCS_A, 21, "Local Coord Unit Vector (YUZL)", "YUZL" }, + + {NITF_BCS_A, 21, "Local Coord Unit Vector (ZUXL)", "ZUXL" }, + {NITF_BCS_A, 21, "Local Coord Unit Vector (ZUYL)", "ZUYL" }, + {NITF_BCS_A, 21, "Local Coord Unit Vector (ZUZL)", "ZUZL" }, + + + {NITF_BCS_A, 2, "Image Row Constant Index", "IR0" }, + {NITF_BCS_A, 2, "Image Row X Index", "IRX" }, + {NITF_BCS_A, 2, "Image Row Y Index", "IRY" }, + {NITF_BCS_A, 2, "Image Row Z Index", "IRZ" }, + + {NITF_BCS_A, 2, "Image Row X^2 Index", "IRXX" }, + {NITF_BCS_A, 2, "Image Row XY Index", "IRXY" }, + {NITF_BCS_A, 2, "Image Row XZ Index", "IRXZ" }, + + + {NITF_BCS_A, 2, "Image Row Y^2 Index", "IRYY" }, + {NITF_BCS_A, 2, "Image Row YZ Index", "IRYZ" }, + + {NITF_BCS_A, 2, "Image Row Z^2 Index", "IRZZ" }, + + + + {NITF_BCS_A, 2, "Image Col Constant Index", "IC0" }, + {NITF_BCS_A, 2, "Image Col X Index", "ICX" }, + {NITF_BCS_A, 2, "Image Col Y Index", "ICY" }, + {NITF_BCS_A, 2, "Image Col Z Index", "ICZ" }, + + {NITF_BCS_A, 2, "Image Col X^2 Index", "ICXX" }, + {NITF_BCS_A, 2, "Image Col XY Index", "ICXY" }, + {NITF_BCS_A, 2, "Image Col XZ Index", "ICXZ" }, + + + {NITF_BCS_A, 2, "Image Col Y^2 Index", "ICYY" }, + {NITF_BCS_A, 2, "Image Col YZ Index", "ICYZ" }, + + {NITF_BCS_A, 2, "Image Col Z^2 Index", "ICZZ" }, + + {NITF_BCS_A, 2, "Ground X Constant Index", "GX0" }, + {NITF_BCS_A, 2, "Ground Y Constant Index", "GY0" }, + {NITF_BCS_A, 2, "Ground Z Constant Index", "GZ0" }, + + {NITF_BCS_A, 2, "Ground Rotation X", "GXR" }, + {NITF_BCS_A, 2, "Ground Rotation Y", "GYR" }, + {NITF_BCS_A, 2, "Ground Rotation Z", "GZR" }, + + {NITF_BCS_A, 2, "Ground Scale", "GS" }, + + {NITF_BCS_A, 2, "Ground X Adj Proportional to X index", "GXX" }, + {NITF_BCS_A, 2, "Ground X Adj Proportional to Y index", "GXY" }, + {NITF_BCS_A, 2, "Ground X Adj Proportional to Z index", "GXZ" }, + + + {NITF_BCS_A, 2, "Ground Y Adj Proportional to X index", "GYX" }, + {NITF_BCS_A, 2, "Ground Y Adj Proportional to Y index", "GYY" }, + {NITF_BCS_A, 2, "Ground Y Adj Proportional to Z index", "GYZ" }, + + {NITF_BCS_A, 2, "Ground Z Adj Proportional to X index", "GZX" }, + {NITF_BCS_A, 2, "Ground Z Adj Proportional to Y index", "GZY" }, + {NITF_BCS_A, 2, "Ground Z Adj Proportional to Z index", "GZZ" }, + + + {NITF_LOOP, 0, NULL, "IGN" }, + + {NITF_BCS_N, 2, "Number of Orig Adj Params in Subgroup", "NUMOPG" }, + + {NITF_LOOP, 0, NITF_FUNCTION, (char*)&numopg}, + + {NITF_BCS_A, 21, "Original Error Covariance Element", "ERRCVG" }, + + {NITF_ENDLOOP, 0, NULL, NULL}, + + {NITF_BCS_N, 1, "Time Correlation Domain Flag", "TCDF" }, + {NITF_BCS_N, 1, "Number of Correlation Segments", "NCSEG" }, + + {NITF_LOOP, 0, NULL, "NCSEG" }, + + {NITF_BCS_A, 21, "Segment Correlation Value", "CORSEG" }, + {NITF_BCS_A, 21, "Segment Tau Value", "TAUSEG" }, + + {NITF_ENDLOOP, 0, NULL, NULL}, /* NCSEG */ + + {NITF_ENDLOOP, 0, NULL, NULL}, /* IGN */ + + + {NITF_LOOP, 0, NITF_FUNCTION, (char*)&mapped}, + {NITF_BCS_A, 21, "Mapping Matrix Element", "MAP" }, + {NITF_ENDLOOP, 0, NULL, NULL}, /* MAP */ + + {NITF_ENDIF, 0, NULL, NULL }, + + {NITF_IF, 0, "eq Y", "INCLUC"}, + + {NITF_BCS_A, 21, "Unmodeled Row Variance", "URR" }, + {NITF_BCS_A, 21, "Unmodeled Row-Column Covariance", "URC" }, + {NITF_BCS_A, 21, "Unmodeled Column Variance", "UCC" }, + {NITF_BCS_N, 1, "Number of Corr Segs for ind-variable Row distance", "UNCSR" }, + + {NITF_LOOP, 0, NULL, "UNCSR" }, + + {NITF_BCS_A, 21, "Segment Correlation Value", "UCORSR" }, + {NITF_BCS_A, 21, "Segment Tau Value", "UTAUSR" }, + + {NITF_ENDLOOP, 0, NULL, NULL}, + + {NITF_BCS_N, 1, "Number of Corr Segs for ind-variable Col distance", "UNCSC" }, + + {NITF_LOOP, 0, NULL, "UNCSC" }, + + {NITF_BCS_A, 21, "Segment Correlation Value", "UCORSC" }, + {NITF_BCS_A, 21, "Segment Tau Value", "UTAUSC" }, + + {NITF_ENDLOOP, 0, NULL, NULL}, + + {NITF_ENDIF, 0, NULL, NULL }, + + {NITF_END, 0, NULL, NULL} + + +}; + + + +NITF_DECLARE_SINGLE_PLUGIN(RSMECA, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/RSMGGA.c b/modules/c/nitf/shared/RSMGGA.c new file mode 100644 index 000000000..bd0bd591c --- /dev/null +++ b/modules/c/nitf/shared/RSMGGA.c @@ -0,0 +1,107 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + +NITF_CXX_GUARD + +static int nxptsXnypts(nitf_TRE* tre, char idx[10][10], int depth, nitf_Error* error) +{ + int nxpts, nypts; + char fname[64]; + nitf_Field* field; + strcpy(fname, "NXPTS"); + strcat(fname, idx[0]); + field = nitf_TRE_getField(tre, fname); + nitf_Field_get(field, &nxpts, NITF_CONV_INT, sizeof(nxpts), error); + + strcpy(fname, "NYPTS"); + strcat(fname, idx[0]); + field = nitf_TRE_getField(tre, fname); + nitf_Field_get(field, &nypts, NITF_CONV_INT, sizeof(nypts), error); + + return nxpts * nypts; +} + +static nitf_TREDescription description[] = { + {NITF_BCS_A, 80, "Image Identifier", "IID" }, + {NITF_BCS_A, 40, "RSM Image Support Data Edition", "EDITION" }, + + {NITF_BCS_N, 3, "Ground-to-image Grid Row Section Number", "GGRSN" }, + {NITF_BCS_N, 3, "Ground-to-image Grid Col Section Number", "GGCSN" }, + + + {NITF_BCS_A, 21, "Ground-to-image Grid Row Fitting Error", "GGRFEP" }, + {NITF_BCS_A, 21, "Ground-to-image Grid Col Fitting Error", "GGCFEP" }, + + {NITF_BCS_A, 1, "Ground-to-image Grid Interp Order", "INTORD" }, + + {NITF_BCS_N, 3, "Number of Grid Planes", "NPLN" }, + {NITF_BCS_A, 21, "Delta Z Between Grid Planes", "DELTAZ" }, + {NITF_BCS_A, 21, "Delta X Between Grid Points", "DELTAX" }, + {NITF_BCS_A, 21, "Delta Y Between Grid Points", "DELTAY" }, + + {NITF_BCS_A, 21, "Z Value of Plane 1", "ZPLN1" }, + {NITF_BCS_A, 21, "X Value of Initial Point in Plane 1", "XIPLN1" }, + {NITF_BCS_A, 21, "Y Value of Initial Point in Plane 1", "YIPLN1" }, + + {NITF_BCS_N, 9, "Ref Image Row Coord Value", "REFROW" }, + {NITF_BCS_N, 9, "Ref Image Col Coord Value", "REFCOL" }, + + {NITF_BCS_N, 2, "Total Num of Image Row Coord Digits", "TNUMRD" }, + {NITF_BCS_N, 2, "Total Num of Image Col Coord Digits", "TNUMCD" }, + + {NITF_BCS_N, 1, "Num of Image Row Coord Fractional Digits", "FNUMRD" }, + {NITF_BCS_N, 1, "Num of Image Col Coord Fractional Digits", "FNUMCD" }, + + /* This [0] value corresponds to second grid plan */ + {NITF_LOOP, 0, "- 1", "NPLN"}, + + {NITF_BCS_N, 4, "Initial Grid Points X Off", "IXO" }, + {NITF_BCS_N, 4, "Initial Grid Points Y Off", "IYO" }, + + {NITF_ENDLOOP, 0, NULL, NULL }, + + {NITF_LOOP, 0, NULL, "NPLN"}, + + {NITF_BCS_N, 3, "Num of Grid Points in the X Direction", "NXPTS" }, + {NITF_BCS_N, 3, "Num of Grid Points in the Y Direction", "NYPTS" }, + + {NITF_LOOP, 0, NITF_FUNCTION, (char*)&nxptsXnypts}, + + {NITF_BCS_A, NITF_TRE_CONDITIONAL_LENGTH, "Grid Point's Row Coord", + "RCOORD", "TNUMRD" }, + {NITF_BCS_A, NITF_TRE_CONDITIONAL_LENGTH, "Grid Point's Col Coord", + "CCOORD", "TNUMCD" }, + + {NITF_ENDLOOP, 0, NULL, NULL }, /* NXPTS x NYPTS */ + {NITF_ENDLOOP, 0, NULL, NULL }, /* NPLN */ + + {NITF_END, 0, NULL, NULL} + +}; + + + +NITF_DECLARE_SINGLE_PLUGIN(RSMGGA, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/RSMGIA.c b/modules/c/nitf/shared/RSMGIA.c new file mode 100644 index 000000000..c0ca2eb10 --- /dev/null +++ b/modules/c/nitf/shared/RSMGIA.c @@ -0,0 +1,76 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_A, 80, "Image Identifier", "IID" }, + {NITF_BCS_A, 40, "RSM Image Support Data Edition", "EDITION" }, + + {NITF_BCS_A, 21, "Low Order Poly Const Coeff for Row", "GR0" }, + {NITF_BCS_A, 21, "Low Order Poly Coeff of X for Row", "GRX" }, + {NITF_BCS_A, 21, "Low Order Poly Coeff of Y for Row", "GRY" }, + {NITF_BCS_A, 21, "Low Order Poly Coeff of Z for Row", "GRZ" }, + + {NITF_BCS_A, 21, "Low Order Poly Coeff of XX for Row", "GRXX" }, + {NITF_BCS_A, 21, "Low Order Poly Coeff of XY for Row", "GRXY" }, + {NITF_BCS_A, 21, "Low Order Poly Coeff of XZ for Row", "GRXZ" }, + + {NITF_BCS_A, 21, "Low Order Poly Coeff of YY for Row", "GRYY" }, + {NITF_BCS_A, 21, "Low Order Poly Coeff of YZ for Row", "GRYZ" }, + + {NITF_BCS_A, 21, "Low Order Poly Coeff of ZZ for Row", "GRZZ" }, + + + {NITF_BCS_A, 21, "Low Order Poly Const Coeff for Col", "GC0" }, + {NITF_BCS_A, 21, "Low Order Poly Coeff of X for Col", "GCX" }, + {NITF_BCS_A, 21, "Low Order Poly Coeff of Y for Col", "GCY" }, + {NITF_BCS_A, 21, "Low Order Poly Coeff of Z for Col", "GCZ" }, + + {NITF_BCS_A, 21, "Low Order Poly Coeff of XX for Col", "GCXX" }, + {NITF_BCS_A, 21, "Low Order Poly Coeff of XY for Col", "GCXY" }, + {NITF_BCS_A, 21, "Low Order Poly Coeff of XZ for Col", "GCXZ" }, + + {NITF_BCS_A, 21, "Low Order Poly Coeff of YY for Col", "GCYY" }, + {NITF_BCS_A, 21, "Low Order Poly Coeff of YZ for Col", "GCYZ" }, + + {NITF_BCS_A, 21, "Low Order Poly Coeff of ZZ for Col", "GCZZ" }, + + {NITF_BCS_N, 3, "Row Number of Image Sections", "GRNIS" }, + {NITF_BCS_N, 3, "Col Number of Image Sections", "GCNIS" }, + {NITF_BCS_N, 3, "Total Number of Image Sections", "GTNIS" }, + + {NITF_BCS_A, 21, "Section Size in Rows", "GRSSIZ" }, + {NITF_BCS_A, 21, "Section Size in Cols", "GCSSIZ" }, + + {NITF_END, 0, NULL, NULL} + + +}; + + + +NITF_DECLARE_SINGLE_PLUGIN(RSMGIA, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/RSMIDA.c b/modules/c/nitf/shared/RSMIDA.c new file mode 100644 index 000000000..28877996e --- /dev/null +++ b/modules/c/nitf/shared/RSMIDA.c @@ -0,0 +1,139 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_A, 80, "Image Identifier", "IID" }, + {NITF_BCS_A, 40, "RSM Image Support Data Edition", "EDITION" }, + {NITF_BCS_A, 40, "Image Sequence Identifier", "ISID" }, + {NITF_BCS_A, 40, "Sensor Identifier", "SID" }, + {NITF_BCS_A, 40, "Sensor Type Identifier", "STID" }, + {NITF_BCS_N, 4, "Year of Image Acquisition", "YEAR" }, + {NITF_BCS_N, 2, "Month of Image Acquisition", "MONTH" }, + {NITF_BCS_N, 2, "Day of Image Acquisition", "DAY" }, + {NITF_BCS_N, 2, "Hour of Image Acquisition", "HOUR" }, + {NITF_BCS_N, 2, "Minute of Image Acquisition", "MINUTE" }, + {NITF_BCS_N, 9, "Second of Image Acquisition", "SECOND" }, + {NITF_BCS_A, 8, "Number of Rows Acquired Simultaneously", "NRG" }, + {NITF_BCS_A, 8, "Number of Columns Acquired Simultaneously", "NCG" }, + {NITF_BCS_A, 21, "Time Between Adjacent Row Groups", "TRG" }, + {NITF_BCS_A, 21, "Time Between Adjacent Column Groups", "TCG" }, + + {NITF_BCS_A, 1, "Ground Domain Form", "GRNDD" }, + {NITF_BCS_A, 21, "Regular Coordinate Origin (XUOR)", "XUOR" }, + {NITF_BCS_A, 21, "Regular Coordinate Origin (YUOR)", "YUOR" }, + {NITF_BCS_A, 21, "Regular Coordinate Origin (ZUOR)", "ZUOR" }, + + {NITF_BCS_A, 21, "Rectangular Coord Unit Vector (XUXR)", "XUXR" }, + {NITF_BCS_A, 21, "Rectangular Coord Unit Vector (XUYR)", "XUYR" }, + {NITF_BCS_A, 21, "Rectangular Coord Unit Vector (XUZR)", "XUZR" }, + + {NITF_BCS_A, 21, "Rectangular Coord Unit Vector (YUXR)", "YUXR" }, + {NITF_BCS_A, 21, "Rectangular Coord Unit Vector (YUYR)", "YUYR" }, + {NITF_BCS_A, 21, "Rectangular Coord Unit Vector (YUZR)", "YUZR" }, + + {NITF_BCS_A, 21, "Rectangular Coord Unit Vector (ZUXR)", "ZUXR" }, + {NITF_BCS_A, 21, "Rectangular Coord Unit Vector (ZUYR)", "ZUYR" }, + {NITF_BCS_A, 21, "Rectangular Coord Unit Vector (ZUZR)", "ZUZR" }, + + {NITF_BCS_A, 21, "Vertex 1 - X coord of the RSM ground domain", "V1X" }, + {NITF_BCS_A, 21, "Vertex 1 - Y coord of the RSM ground domain", "V1Y" }, + {NITF_BCS_A, 21, "Vertex 1 - Z coord of the RSM ground domain", "V1Z" }, + + {NITF_BCS_A, 21, "Vertex 2 - X coord of the RSM ground domain", "V2X" }, + {NITF_BCS_A, 21, "Vertex 2 - Y coord of the RSM ground domain", "V2Y" }, + {NITF_BCS_A, 21, "Vertex 2 - Z coord of the RSM ground domain", "V2Z" }, + + {NITF_BCS_A, 21, "Vertex 3 - X coord of the RSM ground domain", "V3X" }, + {NITF_BCS_A, 21, "Vertex 3 - Y coord of the RSM ground domain", "V3Y" }, + {NITF_BCS_A, 21, "Vertex 3 - Z coord of the RSM ground domain", "V3Z" }, + + {NITF_BCS_A, 21, "Vertex 4 - X coord of the RSM ground domain", "V4X" }, + {NITF_BCS_A, 21, "Vertex 4 - Y coord of the RSM ground domain", "V4Y" }, + {NITF_BCS_A, 21, "Vertex 4 - Z coord of the RSM ground domain", "V4Z" }, + + {NITF_BCS_A, 21, "Vertex 5 - X coord of the RSM ground domain", "V5X" }, + {NITF_BCS_A, 21, "Vertex 5 - Y coord of the RSM ground domain", "V5Y" }, + {NITF_BCS_A, 21, "Vertex 5 - Z coord of the RSM ground domain", "V5Z" }, + + + {NITF_BCS_A, 21, "Vertex 6 - X coord of the RSM ground domain", "V6X" }, + {NITF_BCS_A, 21, "Vertex 6 - Y coord of the RSM ground domain", "V6Y" }, + {NITF_BCS_A, 21, "Vertex 6 - Z coord of the RSM ground domain", "V6Z" }, + + {NITF_BCS_A, 21, "Vertex 7 - X coord of the RSM ground domain", "V7X" }, + {NITF_BCS_A, 21, "Vertex 7 - Y coord of the RSM ground domain", "V7Y" }, + {NITF_BCS_A, 21, "Vertex 7 - Z coord of the RSM ground domain", "V7Z" }, + + {NITF_BCS_A, 21, "Vertex 8 - X coord of the RSM ground domain", "V8X" }, + {NITF_BCS_A, 21, "Vertex 8 - Y coord of the RSM ground domain", "V8Y" }, + {NITF_BCS_A, 21, "Vertex 8 - Z coord of the RSM ground domain", "V8Z" }, + + {NITF_BCS_A, 21, "Ground Reference Point X", "GRPX" }, + {NITF_BCS_A, 21, "Ground Reference Point Y", "GRPY" }, + {NITF_BCS_A, 21, "Ground Reference Point Z", "GRPZ" }, + + {NITF_BCS_A, 8, "Number of Rows in Full Image", "FULLR" }, + {NITF_BCS_A, 8, "Number of Cols in Full Image", "FULLC" }, + + {NITF_BCS_A, 8, "Minimum Row", "MINR" }, + {NITF_BCS_A, 8, "Maximum Row", "MAXR" }, + + {NITF_BCS_A, 8, "Minimum Col", "MINC" }, + {NITF_BCS_A, 8, "Maximum Col", "MAXC" }, + + {NITF_BCS_A, 21, "Illum Elevation Angle Const Coeff", "IE0" }, + {NITF_BCS_A, 21, "Illum Elevation Angle Coeff Per Row", "IER" }, + {NITF_BCS_A, 21, "Illum Elevation Angle Coeff Per Col", "IEC" }, + + {NITF_BCS_A, 21, "Illum Elevation Angle Coeff Per Row^2", "IERR" }, + {NITF_BCS_A, 21, "Illum Elevation Angle Coeff Per Row-Col", "IERC" }, + {NITF_BCS_A, 21, "Illum Elevation Angle Coeff Per Col^2", "IERC" }, + + {NITF_BCS_A, 21, "Illum Azimuth Angle Const", "IE0" }, + {NITF_BCS_A, 21, "Illum Azimuth Angle Coeff Per Row", "IAR" }, + {NITF_BCS_A, 21, "Illum Azimuth Angle Coeff Per Col", "IAC" }, + + {NITF_BCS_A, 21, "Illum Azimuth Angle Coeff Per Row^2", "IARR" }, + {NITF_BCS_A, 21, "Illum Azimuth Angle Coeff Per Row-Col", "IARC" }, + {NITF_BCS_A, 21, "Illum Azimuth Angle Coeff Per Col^2", "IARC" }, + + {NITF_BCS_A, 21, "Sensor x-position", "SPX" }, + {NITF_BCS_A, 21, "Sensor x-velocity", "SVX" }, + {NITF_BCS_A, 21, "Sensor x-acceleration", "SAX" }, + + {NITF_BCS_A, 21, "Sensor y-position", "SPY" }, + {NITF_BCS_A, 21, "Sensor y-velocity", "SVY" }, + {NITF_BCS_A, 21, "Sensor y-acceleration", "SAY" }, + + {NITF_BCS_A, 21, "Sensor z-position", "SPZ" }, + {NITF_BCS_A, 21, "Sensor z-velocity", "SVZ" }, + {NITF_BCS_A, 21, "Sensor z-acceleration", "SAZ" }, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(RSMIDA, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/RSMPCA.c b/modules/c/nitf/shared/RSMPCA.c new file mode 100644 index 000000000..e4e428dd7 --- /dev/null +++ b/modules/c/nitf/shared/RSMPCA.c @@ -0,0 +1,110 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_A, 80, "Image Identifier", "IID" }, + {NITF_BCS_A, 40, "RSM Image Support Data Edition", "EDITION" }, + + {NITF_BCS_N, 3, "Row Section Number", "RSN" }, + {NITF_BCS_N, 3, "Column Section Number", "CSN" }, + + {NITF_BCS_A, 21, "Row Fitting Error", "RFEP" }, + {NITF_BCS_A, 21, "Col Fitting Error", "CFEP" }, + + {NITF_BCS_A, 21, "Row Normalization Offset", "RNRMO" }, + {NITF_BCS_A, 21, "Col Normalization Offset", "CNRMO" }, + + {NITF_BCS_A, 21, "X Normalization Offset", "XNRMO" }, + {NITF_BCS_A, 21, "Y Normalization Offset", "YNRMO" }, + {NITF_BCS_A, 21, "Z Normalization Offset", "ZNRMO" }, + + {NITF_BCS_A, 21, "Row Normalization Scale Factor", "RNRMSF" }, + {NITF_BCS_A, 21, "Col Normalization Scale Factor", "CNRMSF" }, + + {NITF_BCS_A, 21, "X Normalization Scale Factor", "XNRMSF" }, + {NITF_BCS_A, 21, "Y Normalization Scale Factor", "YNRMSF" }, + {NITF_BCS_A, 21, "Z Normalization Scale Factor", "ZNRMSF" }, + + {NITF_BCS_N, 1, "Row Numerator Poly Max Power of X", "RNPWRX" }, + {NITF_BCS_N, 1, "Row Numerator Poly Max Power of Y", "RNPWRY" }, + {NITF_BCS_N, 1, "Row Numerator Poly Max Power of Z", "RNPWRZ" }, + + {NITF_BCS_N, 3, "Row Numerator Poly Number of Poly Terms", "RNTRMS" }, + + {NITF_LOOP, 0, NULL, "RNTRMS"}, + + {NITF_BCS_A, 21, "Poly Coeff", "RNPCF" }, + + {NITF_ENDLOOP, 0, NULL, NULL}, + + + {NITF_BCS_N, 1, "Row Denominator Poly Max Power of X", "RDPWRX" }, + {NITF_BCS_N, 1, "Row Denominator Poly Max Power of Y", "RDPWRY" }, + {NITF_BCS_N, 1, "Row Denominator Poly Max Power of Z", "RDPWRZ" }, + + {NITF_BCS_N, 3, "Row Denominator Poly Number of Poly Terms", "RDTRMS" }, + + {NITF_LOOP, 0, NULL, "RDTRMS"}, + + {NITF_BCS_A, 21, "Poly Coeff", "RDPCF" }, + + {NITF_ENDLOOP, 0, NULL, NULL}, + + + + {NITF_BCS_N, 1, "Row Numerator Poly Max Power of X", "CNPWRX" }, + {NITF_BCS_N, 1, "Row Numerator Poly Max Power of Y", "CNPWRY" }, + {NITF_BCS_N, 1, "Row Numerator Poly Max Power of Z", "CNPWRZ" }, + + {NITF_BCS_N, 3, "Row Numerator Poly Number of Poly Terms", "CNTRMS" }, + + {NITF_LOOP, 0, NULL, "CNTRMS"}, + + {NITF_BCS_A, 21, "Poly Coeff", "CNPCF" }, + + {NITF_ENDLOOP, 0, NULL, NULL}, + + + {NITF_BCS_N, 1, "Row Denominator Poly Max Power of X", "CDPWRX" }, + {NITF_BCS_N, 1, "Row Denominator Poly Max Power of Y", "CDPWRY" }, + {NITF_BCS_N, 1, "Row Denominator Poly Max Power of Z", "CDPWRZ" }, + + {NITF_BCS_N, 3, "Row Denominator Poly Number of Poly Terms", "CDTRMS" }, + + {NITF_LOOP, 0, NULL, "CDTRMS"}, + + {NITF_BCS_A, 21, "Poly Coeff", "CDPCF" }, + + {NITF_ENDLOOP, 0, NULL, NULL}, + + {NITF_END, 0, NULL, NULL} + + +}; + +NITF_DECLARE_SINGLE_PLUGIN(RSMPCA, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/RSMPIA.c b/modules/c/nitf/shared/RSMPIA.c new file mode 100644 index 000000000..c85b002db --- /dev/null +++ b/modules/c/nitf/shared/RSMPIA.c @@ -0,0 +1,72 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_A, 80, "Image Identifier", "IID" }, + {NITF_BCS_A, 40, "RSM Image Support Data Edition", "EDITION" }, + + {NITF_BCS_A, 21, "Low Order Poly Const Coeff for Row", "R0" }, + + {NITF_BCS_A, 21, "Low Order Poly Coff of X for Row", "RX" }, + {NITF_BCS_A, 21, "Low Order Poly Coff of Y for Row", "RY" }, + {NITF_BCS_A, 21, "Low Order Poly Coff of Z for Row", "RZ" }, + + {NITF_BCS_A, 21, "Low Order Poly Coff of XX for Row", "RXX" }, + {NITF_BCS_A, 21, "Low Order Poly Coff of XY for Row", "RXY" }, + {NITF_BCS_A, 21, "Low Order Poly Coff of XZ for Row", "RXZ" }, + + {NITF_BCS_A, 21, "Low Order Poly Coff of YY for Row", "RYY" }, + {NITF_BCS_A, 21, "Low Order Poly Coff of YZ for Row", "RYZ" }, + + {NITF_BCS_A, 21, "Low Order Poly Coff of ZZ for Row", "RZZ" }, + + {NITF_BCS_A, 21, "Low Order Poly Const Coeff for Col", "C0" }, + + {NITF_BCS_A, 21, "Low Order Poly Coff of X for Col", "CX" }, + {NITF_BCS_A, 21, "Low Order Poly Coff of Y for Col", "CY" }, + {NITF_BCS_A, 21, "Low Order Poly Coff of Z for Col", "CZ" }, + + {NITF_BCS_A, 21, "Low Order Poly Coff of XX for Col", "CXX" }, + {NITF_BCS_A, 21, "Low Order Poly Coff of XY for Col", "CXY" }, + {NITF_BCS_A, 21, "Low Order Poly Coff of XZ for Col", "CXZ" }, + + {NITF_BCS_A, 21, "Low Order Poly Coff of YY for Col", "CYY" }, + {NITF_BCS_A, 21, "Low Order Poly Coff of YZ for Col", "CYZ" }, + {NITF_BCS_A, 21, "Low Order Poly Coff of ZZ for Col", "CZZ" }, + + {NITF_BCS_N, 3, "Row Number of Image Sections", "RNIS" }, + {NITF_BCS_N, 3, "Column Number of Image Sections", "CNIS" }, + {NITF_BCS_N, 3, "Total Number of Image Sections", "TNIS" }, + + {NITF_BCS_A, 21, "Section Size in Rows", "RSSIZ" }, + {NITF_BCS_A, 21, "Section Size in Cols", "CSSIZ" }, + + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(RSMPIA, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/SECTGA.c b/modules/c/nitf/shared/SECTGA.c new file mode 100644 index 000000000..05b4a0fda --- /dev/null +++ b/modules/c/nitf/shared/SECTGA.c @@ -0,0 +1,37 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_A, 12, "Secondary Target ID", "SEC_ID" }, + {NITF_BCS_A, 15, "Secondary Target BE No", "SEC_BE" }, + {NITF_BCS_A, 1, "reserved 1", "RESVD001" }, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(SECTGA, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/SENSRA.c b/modules/c/nitf/shared/SENSRA.c new file mode 100644 index 000000000..93684a178 --- /dev/null +++ b/modules/c/nitf/shared/SENSRA.c @@ -0,0 +1,58 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_N, 8, "Ref Row", "REFROW" }, + {NITF_BCS_N, 8, "Ref Col", "REFCOL" }, + {NITF_BCS_A, 6, "Sensor Model", "SNSMODEL" }, + {NITF_BCS_A, 3, "Sensor Mount", "SNSMOUNT" }, + {NITF_BCS_A, 21, "Sensor Loc", "SENSLOC" }, + {NITF_BCS_A, 1, "Sensor Alt Src", "SNALTSRC" }, + {NITF_BCS_A, 6, "Sensor Alt", "SENSALT" }, + {NITF_BCS_A, 1, "Sensor Alt Unit", "SNALUNIT" }, + {NITF_BCS_A, 5, "Sensor AGL", "SENSAGL" }, + {NITF_BCS_A, 7, "Sensor Pitch", "SNSPITCH" }, + {NITF_BCS_A, 8, "Sensor Roll", "SENSROLL" }, + {NITF_BCS_A, 8, "Sensor Yaw", "SENSYAW" }, + {NITF_BCS_A, 7, "Platform Pitch", "PLTPITCH" }, + {NITF_BCS_A, 8, "Platform Roll", "PLATROLL" }, + {NITF_BCS_A, 5, "Platform Hdg", "PLATHDG" }, + {NITF_BCS_A, 1, "Ground Spd Src", "GRSPDSRC" }, + {NITF_BCS_A, 6, "Ground Speed", "GRDSPEED" }, + {NITF_BCS_A, 1, "Ground Spd Unit", "GRSPUNIT" }, + {NITF_BCS_A, 5, "Ground Track", "GRDTRACK" }, + {NITF_BCS_A, 5, "Vertical Vel", "VERTVEL" }, + {NITF_BCS_A, 1, "Vert Vel Unit", "VERTVELU" }, + {NITF_BCS_A, 4, "Swath Frames", "SWATHFRM" }, + {NITF_BCS_N, 4, "N Swaths", "NSWATHS" }, + {NITF_BCS_N, 3, "Spot Num", "SPOTNUM" }, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(SENSRA, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/SENSRB.c b/modules/c/nitf/shared/SENSRB.c new file mode 100644 index 000000000..50f09ba73 --- /dev/null +++ b/modules/c/nitf/shared/SENSRB.c @@ -0,0 +1,407 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_A, 1, "General Data", "GENERAL_DATA"}, /* 01 */ + {NITF_IF, 0, "eq Y", "GENERAL_DATA"}, + {NITF_BCS_A, 25, "Sensor Name", "SENSOR"}, /* 01a */ + {NITF_BCS_A, 32, "Sensor URI", "SENSOR_URI"}, /* 01b */ + {NITF_BCS_A, 25, "Platform Common Name", "PLATFORM"}, /* 01c */ + {NITF_BCS_A, 32, "Platform URI", "PLATFORM_URI"}, /* 01d */ + {NITF_BCS_A, 10, "Operation Domain", "OPERATION_DOMAIN"}, /* 01e */ + {NITF_BCS_N, 1, "Content Level", "CONTENT_LEVEL"}, /* 01f */ + {NITF_BCS_A, 5, "Geodetic System", "GEODETIC_SYSTEM"}, /* 01g */ + {NITF_BCS_A, 1, "Geodetic Type", "GEODETIC_TYPE"}, /* 01h */ + {NITF_BCS_A, 3, "Elevation Datum", "ELEVATION_DATUM"}, /* 01i */ + {NITF_BCS_A, 2, "Length Unit", "LENGTH_UNIT"}, /* 01j */ + {NITF_BCS_A, 3, "Angular Unit", "ANGULAR_UNIT"}, /* 01k */ + {NITF_BCS_N, 8, "Start Date", "START_DATE"}, /* 01l */ + {NITF_BCS_N, 14, "Start Time", "START_TIME"}, /* 01m */ + {NITF_BCS_N, 8, "End Date", "END_DATE"}, /* 01n */ + {NITF_BCS_N, 14, "End Time", "END_TIME"}, /* 01o */ + {NITF_BCS_N, 2, "Generation Count", "GENERATION_COUNT"}, /* 01p */ + {NITF_BCS_N, 8, "Generation Date", "GENERATION_DATE"}, /* 01q */ + {NITF_BCS_N, 10, "Generation Time", "GENERATION_TIME"}, /* 01r */ + {NITF_ENDIF, 0, NULL, NULL}, + + {NITF_BCS_A, 1, "Sensor Array Data", "SENSOR_ARRAY_DATA"}, /* 02 */ + {NITF_IF, 0, "eq Y", "SENSOR_ARRAY_DATA"}, + {NITF_BCS_A, 20, "Detection", "DETECTION"}, /* 02a */ + {NITF_BCS_N, 8, "Row Detectors", "ROW_DETECTORS"}, /* 02b */ + {NITF_BCS_N, 8, "Column Detectors", "COLUMN_DETECTORS"}, /* 02c */ + {NITF_BCS_N, 8, "Row Metric", "ROW_METRIC"}, /* 02d */ + {NITF_BCS_N, 8, "Column Metric", "COLUMN_METRIC"}, /* 02e */ + {NITF_BCS_N, 8, "Focal Length", "FOCAL_LENGTH"}, /* 02f */ + {NITF_BCS_N, 8, "Row Field of View", "ROW_FOV"}, /* 02g */ + {NITF_BCS_N, 8, "Column Field of View", "COLUMN_FOV"}, /* 02h */ + {NITF_BCS_A, 1, "Calibrated", "CALIBRATED"}, /* 02i */ + {NITF_ENDIF, 0, NULL, NULL}, + + {NITF_BCS_A, 1, "Sensor Calibration Data", "SENSOR_CALIBRATION_DATA"}, /* 03 */ + {NITF_IF, 0, "eq Y", "SENSOR_CALIBRATION_DATA"}, + {NITF_BCS_A, 2, "Calibration Unit System", "CALIBRATION_UNIT"}, /* 03a */ + {NITF_BCS_N, 9, "Principal Point Offset X", "PRINCIPAL_POINT_OFFSET_X"}, /* 03b */ + {NITF_BCS_N, 9, "Principal Point Offset Y", "PRINCIPAL_POINT_OFFSET_Y"}, /* 03c */ + {NITF_BCS_A, 12, "Radial Distortion Coeff 1", "RADIAL_DISTORT_1"}, /* 03d */ + {NITF_BCS_A, 12, "Radial Distortion Coeff 2", "RADIAL_DISTORT_2"}, /* 03e */ + {NITF_BCS_A, 12, "Radial Distortion Coeff 3", "RADIAL_DISTORT_3"}, /* 03f */ + {NITF_BCS_N, 9, "Radial Distortion Fit Limit", "RADIAL_DISTORT_LIMIT"},/* 03g */ + {NITF_BCS_A, 12, "Decentering Distortion Coeff 1","DECENT_DISTORT_1"}, /* 03h */ + {NITF_BCS_A, 12, "Decentering Distortion Coeff 2","DECENT_DISTORT_2"}, /* 03i */ + {NITF_BCS_A, 12, "Affinity Distortion Coeff 1", "AFFINITY_DISTORT_1"}, /* 03j */ + {NITF_BCS_A, 12, "Affinity Distortion Coeff 2", "AFFINITY_DISTORT_2"}, /* 03k */ + {NITF_BCS_N, 8, "Calibration Date", "CALIBRATION_DATE"}, /* 03l */ + {NITF_ENDIF, 0, NULL, NULL}, + + {NITF_BCS_A, 1, "Image Formation Data", "IMAGE_FORMATION_DATA"},/* 04 */ + {NITF_IF, 0, "eq Y", "IMAGE_FORMATION_DATA"}, + {NITF_BCS_A, 15, "Imaging Method", "METHOD"}, /* 04a */ + {NITF_BCS_A, 3, "Imaging Mode", "MODE"}, /* 04b */ + {NITF_BCS_N, 8, "Row Count", "ROW_COUNT"}, /* 04c */ + {NITF_BCS_N, 8, "Column Count", "COLUMN_COUNT"}, /* 04d */ + {NITF_BCS_N, 8, "Row Detection Set", "ROW_SET"}, /* 04e */ + {NITF_BCS_N, 8, "Column Detection Set", "COLUMN_SET"}, /* 04f */ + {NITF_BCS_N, 10, "Row Detection Rate", "ROW_RATE"}, /* 04g */ + {NITF_BCS_N, 10, "Column Detection Rate", "COLUMN_RATE"}, /* 04h */ + {NITF_BCS_N, 8, "First Collected Pixel Row", "FIRST_PIXEL_ROW"}, /* 04i */ + {NITF_BCS_N, 8, "First Collected Pixel Column", "FIRST_PIXEL_COLUMN"}, /* 04j */ + {NITF_BCS_N, 1, "Image Transform Parameter Count","TRANSFORM_PARAMS"}, /* 04k */ + {NITF_IF, 0, ">= 1", "TRANSFORM_PARAMS"}, + {NITF_BCS_A, 12, "Image Transform Parameter 1", "TRANSFORM_PARAM_1"}, /* 04l */ + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, ">= 2", "TRANSFORM_PARAMS"}, + {NITF_BCS_A, 12, "Image Transform Parameter 2", "TRANSFORM_PARAM_2"}, /* 04m */ + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, ">= 3", "TRANSFORM_PARAMS"}, + {NITF_BCS_A, 12, "Image Transform Parameter 3", "TRANSFORM_PARAM_3"}, /* 04n */ + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, ">= 4", "TRANSFORM_PARAMS"}, + {NITF_BCS_A, 12, "Image Transform Parameter 4", "TRANSFORM_PARAM_4"}, /* 04o */ + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, ">= 5", "TRANSFORM_PARAMS"}, + {NITF_BCS_A, 12, "Image Transform Parameter 5", "TRANSFORM_PARAM_5"}, /* 04p */ + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, ">= 6", "TRANSFORM_PARAMS"}, + {NITF_BCS_A, 12, "Image Transform Parameter 6", "TRANSFORM_PARAM_6"}, /* 04q */ + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, ">= 7", "TRANSFORM_PARAMS"}, + {NITF_BCS_A, 12, "Image Transform Parameter 7", "TRANSFORM_PARAM_7"}, /* 04r */ + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, ">= 8", "TRANSFORM_PARAMS"}, + {NITF_BCS_A, 12, "Image Transform Parameter 8", "TRANSFORM_PARAM_8"}, /* 04s */ + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_ENDIF, 0, NULL, NULL}, + + {NITF_BCS_N, 12, "Reference Time", "REFERENCE_TIME"}, /* 05a */ + {NITF_BCS_N, 8, "Reference Pixel Row", "REFERENCE_ROW"}, /* 05b */ + {NITF_BCS_N, 8, "Reference Pixel Column", "REFERENCE_COLUMN"}, /* 05c */ + + {NITF_BCS_N, 11, "Latitude or X", "LATITUDE_OR_X"}, /* 06a */ + {NITF_BCS_N, 12, "Longitude or Y", "LONGITUDE_OR_Y"}, /* 06b */ + {NITF_BCS_N, 11, "Altitude or Z", "ALTITUDE_OR_Z"}, /* 06c */ + {NITF_BCS_N, 8, "Sensor X Position Offset", "SENSOR_X_OFFSET"}, /* 06d */ + {NITF_BCS_N, 8, "Sensor Y Position Offset", "SENSOR_Y_OFFSET"}, /* 06e */ + {NITF_BCS_N, 8, "Sensor Z Position Offset", "SENSOR_Z_OFFSET"}, /* 06f */ + + {NITF_BCS_A, 1, "Attitude Euler Angles", "ATTITUDE_EULER_ANGLES"},/* 07 */ + {NITF_IF, 0, "eq Y", "ATTITUDE_EULER_ANGLES"}, + {NITF_BCS_N, 1, "Sensor Angle Model", "SENSOR_ANGLE_MODEL"}, /* 07a */ + {NITF_BCS_N, 10, "Sensor Angle 1", "SENSOR_ANGLE_1"}, /* 07b */ + {NITF_BCS_N, 9, "Sensor Angle 2", "SENSOR_ANGLE_2"}, /* 07c */ + {NITF_BCS_N, 10, "Sensor Angle 3", "SENSOR_ANGLE_3"}, /* 07d */ + {NITF_BCS_A, 1, "Platform Relative Angles", "PLATFORM_RELATIVE"}, /* 07e */ + {NITF_BCS_N, 9, "Platform Heading", "PLATFORM_HEADING"}, /* 07f */ + {NITF_BCS_N, 9, "Platform Pitch", "PLATFORM_PITCH"}, /* 07g */ + {NITF_BCS_N, 10, "Platform Roll", "PLATFORM_ROLL"}, /* 07h */ + {NITF_ENDIF, 0, NULL, NULL}, + + {NITF_BCS_A, 1, "Attitude Unit Vectors", "ATTITUDE_UNIT_VECTORS"},/* 08 */ + {NITF_IF, 0, "eq Y", "ATTITUDE_UNIT_VECTORS"}, + {NITF_BCS_N, 10, "Image Coord X Unit Vector 1", "ICX_NORTH_OR_X"}, /* 08a */ + {NITF_BCS_N, 10, "Image Coord X Unit Vector 2", "ICX_EAST_OR_Y"}, /* 08b */ + {NITF_BCS_N, 10, "Image Coord X Unit Vector 3", "ICX_DOWN_OR_Z"}, /* 08c */ + {NITF_BCS_N, 10, "Image Coord Y Unit Vector 1", "ICY_NORTH_OR_X"}, /* 08d */ + {NITF_BCS_N, 10, "Image Coord Y Unit Vector 2", "ICY_EAST_OR_Y"}, /* 08e */ + {NITF_BCS_N, 10, "Image Coord Y Unit Vector 3", "ICY_DOWN_OR_Z"}, /* 08f */ + {NITF_BCS_N, 10, "Image Coord Z Unit Vector 1", "ICZ_NORTH_OR_X"}, /* 08g */ + {NITF_BCS_N, 10, "Image Coord Z Unit Vector 2", "ICZ_EAST_OR_Y"}, /* 08h */ + {NITF_BCS_N, 10, "Image Coord Z Unit Vector 3", "ICZ_DOWN_OR_Z"}, /* 08i */ + {NITF_ENDIF, 0, NULL, NULL}, + + {NITF_BCS_A, 1, "Attitude Quaternion", "ATTITUDE_QUATERNION"}, /* 09 */ + {NITF_IF, 0, "eq Y", "ATTITUDE_QUATERNION"}, + {NITF_BCS_N, 10, "Attitude Quaternion Vector 1", "ATTITUDE_Q1"}, /* 09a */ + {NITF_BCS_N, 10, "Attitude Quaternion Vector 2", "ATTITUDE_Q2"}, /* 09b */ + {NITF_BCS_N, 10, "Attitude Quaternion Vector 3", "ATTITUDE_Q3"}, /* 09c */ + {NITF_BCS_N, 10, "Attitude Scalar Component", "ATTITUDE_Q4"}, /* 09d */ + {NITF_ENDIF, 0, NULL, NULL}, + + {NITF_BCS_A, 1, "Sensor Velocity Data", "SENSOR_VELOCITY_DATA"},/* 10 */ + {NITF_IF, 0, "eq Y", "SENSOR_VELOCITY_DATA"}, + {NITF_BCS_N, 9, "Sensor North Velocity", "VELOCITY_NORTH_OR_X"}, /* 10a */ + {NITF_BCS_N, 9, "Sensor East Velocity", "VELOCITY_EAST_OR_Y"}, /* 10b */ + {NITF_BCS_N, 9, "Sensor Down Velocity", "VELOCITY_DOWN_OR_Z"}, /* 10c */ + {NITF_ENDIF, 0, NULL, NULL}, + + {NITF_BCS_N, 2, "Point Set Data", "POINT_SET_DATA"}, /* 11 */ + {NITF_LOOP, 0, NULL, "POINT_SET_DATA"}, + {NITF_BCS_A, 25, "Point Set Type", "POINT_SET_TYPE"}, /* 11a */ + {NITF_BCS_N, 3, "Point Count", "POINT_COUNT"}, /* 11b */ + {NITF_LOOP, 0, NULL, "POINT_COUNT"}, + {NITF_BCS_N, 8, "Point Row Location", "P_ROW"}, /* 11c */ + {NITF_BCS_N, 8, "Point Column Location", "P_COLUMN"}, /* 11d */ + {NITF_BCS_N, 10, "Point Latitude", "P_LATITUDE"}, /* 11e */ + {NITF_BCS_N, 11, "Point Longitude", "P_LONGITUDE"}, /* 11f */ + {NITF_BCS_N, 6, "Point Elevation", "P_ELEVATION"}, /* 11g */ + {NITF_BCS_N, 8, "Point Range", "P_RANGE"}, /* 11h */ + {NITF_ENDLOOP,0, NULL, NULL}, + {NITF_ENDLOOP,0, NULL, NULL}, + + /** Time Stamped Data has different types, sizes, and counts depending on + the value of TIME_STAMP_TYPE. There's not easy way to handle this right + now so we'll use lots of NITF_IF statements. + **/ + {NITF_BCS_N, 2, "Time Stamped Data", "TIME_STAMPED_DATA_SETS"},/* 12 */ + {NITF_LOOP, 0, NULL, "TIME_STAMPED_DATA_SETS"}, + {NITF_BCS_A, 3, "Time Stamp Type", "TIME_STAMP_TYPE"}, /* 12a */ + {NITF_BCS_N, 4, "Time Stamp Parameter Count", "TIME_STAMP_COUNT"}, /* 12b */ + {NITF_LOOP, 0, NULL, "TIME_STAMP_COUNT"}, + {NITF_BCS_N, 12, "Time Stamp Time", "TIME_STAMP_TIME"}, /* 12c */ + + /** Start Time Stamped Data **/ + {NITF_IF, 0, "eq 06a", "TIME_STAMP_TYPE"}, /* 12d */ + {NITF_BCS_N, 11, "Time Stamp Value", "TIME_STAMP_VALUE"}, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq 06b", "TIME_STAMP_TYPE"}, + {NITF_BCS_N, 12, "Time Stamp Value", "TIME_STAMP_VALUE"}, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq 06c", "TIME_STAMP_TYPE"}, + {NITF_BCS_N, 11, "Time Stamp Value", "TIME_STAMP_VALUE"}, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq 06d", "TIME_STAMP_TYPE"}, + {NITF_BCS_N, 8, "Time Stamp Value", "TIME_STAMP_VALUE"}, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq 06e", "TIME_STAMP_TYPE"}, + {NITF_BCS_N, 8, "Time Stamp Value", "TIME_STAMP_VALUE"}, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq 06f", "TIME_STAMP_TYPE"}, + {NITF_BCS_N, 8, "Time Stamp Value", "TIME_STAMP_VALUE"}, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq 07b", "TIME_STAMP_TYPE"}, + {NITF_BCS_N, 10, "Time Stamp Value", "TIME_STAMP_VALUE"}, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq 07c", "TIME_STAMP_TYPE"}, + {NITF_BCS_N, 9, "Time Stamp Value", "TIME_STAMP_VALUE"}, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq 07d", "TIME_STAMP_TYPE"}, + {NITF_BCS_N, 10, "Time Stamp Value", "TIME_STAMP_VALUE"}, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq 07f", "TIME_STAMP_TYPE"}, + {NITF_BCS_N, 9, "Time Stamp Value", "TIME_STAMP_VALUE"}, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq 07g", "TIME_STAMP_TYPE"}, + {NITF_BCS_N, 9, "Time Stamp Value", "TIME_STAMP_VALUE"}, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq 07h", "TIME_STAMP_TYPE"}, + {NITF_BCS_N, 10, "Time Stamp Value", "TIME_STAMP_VALUE"}, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq 08a", "TIME_STAMP_TYPE"}, + {NITF_BCS_N, 10, "Time Stamp Value", "TIME_STAMP_VALUE"}, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq 08b", "TIME_STAMP_TYPE"}, + {NITF_BCS_N, 10, "Time Stamp Value", "TIME_STAMP_VALUE"}, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq 08c", "TIME_STAMP_TYPE"}, + {NITF_BCS_N, 10, "Time Stamp Value", "TIME_STAMP_VALUE"}, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq 08d", "TIME_STAMP_TYPE"}, + {NITF_BCS_N, 10, "Time Stamp Value", "TIME_STAMP_VALUE"}, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq 08e", "TIME_STAMP_TYPE"}, + {NITF_BCS_N, 10, "Time Stamp Value", "TIME_STAMP_VALUE"}, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq 08f", "TIME_STAMP_TYPE"}, + {NITF_BCS_N, 10, "Time Stamp Value", "TIME_STAMP_VALUE"}, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq 08g", "TIME_STAMP_TYPE"}, + {NITF_BCS_N, 10, "Time Stamp Value", "TIME_STAMP_VALUE"}, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq 08h", "TIME_STAMP_TYPE"}, + {NITF_BCS_N, 10, "Time Stamp Value", "TIME_STAMP_VALUE"}, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq 08i", "TIME_STAMP_TYPE"}, + {NITF_BCS_N, 10, "Time Stamp Value", "TIME_STAMP_VALUE"}, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq 09a", "TIME_STAMP_TYPE"}, + {NITF_BCS_N, 10, "Time Stamp Value", "TIME_STAMP_VALUE"}, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq 09b", "TIME_STAMP_TYPE"}, + {NITF_BCS_N, 10, "Time Stamp Value", "TIME_STAMP_VALUE"}, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq 09c", "TIME_STAMP_TYPE"}, + {NITF_BCS_N, 10, "Time Stamp Value", "TIME_STAMP_VALUE"}, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq 09d", "TIME_STAMP_TYPE"}, + {NITF_BCS_N, 10, "Time Stamp Value", "TIME_STAMP_VALUE"}, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq 10a", "TIME_STAMP_TYPE"}, + {NITF_BCS_N, 9, "Time Stamp Value", "TIME_STAMP_VALUE"}, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq 10b", "TIME_STAMP_TYPE"}, + {NITF_BCS_N, 9, "Time Stamp Value", "TIME_STAMP_VALUE"}, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq 10c", "TIME_STAMP_TYPE"}, + {NITF_BCS_N, 9, "Time Stamp Value", "TIME_STAMP_VALUE"}, + {NITF_ENDIF, 0, NULL, NULL}, + /** End Time Stamped Data **/ + {NITF_ENDLOOP,0, NULL, NULL}, + {NITF_ENDLOOP,0, NULL, NULL}, + + /** Pixel Referenced Data has different types, sizes, and counts depending on + the value of PIXEL_REFERENCE_TYPE. There's not easy way to handle this right + now so we'll use lots of NITF_IF statements. + **/ + {NITF_BCS_N, 2, "Pixel Reference Data", "PIXEL_REFERENCED_DATA_SETS"},/* 13 */ + {NITF_LOOP, 0, NULL, "PIXEL_REFERENCED_DATA_SETS"}, + {NITF_BCS_A, 3, "Pixel Reference Type", "PIXEL_REFERENCE_TYPE"}, /* 13a */ + {NITF_BCS_N, 4, "Pixel Reference Parameter Count","PIXEL_REFERENCE_COUNT"},/* 13b */ + {NITF_LOOP, 0, NULL, "PIXEL_REFERENCE_COUNT"}, + {NITF_BCS_N, 8, "Pixel Reference Row", "PIXEL_REFERENCE_ROW"}, /* 13c */ + {NITF_BCS_N, 8, "Pixel Reference Column", "PIXEL_REFERENCE_COLUMN"}, /* 13d */ + + /** Start Pixel Referenced Data **/ + {NITF_IF, 0, "eq 06a", "PIXEL_REFERENCE_TYPE"}, /* 13e */ + {NITF_BCS_N, 11, "Pixel Reference Value", "PIXEL_REFERENCE_VALUE"}, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq 06b", "PIXEL_REFERENCE_TYPE"}, + {NITF_BCS_N, 12, "Pixel Reference Value", "PIXEL_REFERENCE_VALUE"}, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq 06c", "PIXEL_REFERENCE_TYPE"}, + {NITF_BCS_N, 11, "Pixel Reference Value", "PIXEL_REFERENCE_VALUE"}, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq 06d", "PIXEL_REFERENCE_TYPE"}, + {NITF_BCS_N, 8, "Pixel Reference Value", "PIXEL_REFERENCE_VALUE"}, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq 06e", "PIXEL_REFERENCE_TYPE"}, + {NITF_BCS_N, 8, "Pixel Reference Value", "PIXEL_REFERENCE_VALUE"}, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq 06f", "PIXEL_REFERENCE_TYPE"}, + {NITF_BCS_N, 8, "Pixel Reference Value", "PIXEL_REFERENCE_VALUE"}, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq 07b", "PIXEL_REFERENCE_TYPE"}, + {NITF_BCS_N, 10, "Pixel Reference Value", "PIXEL_REFERENCE_VALUE"}, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq 07c", "PIXEL_REFERENCE_TYPE"}, + {NITF_BCS_N, 9, "Pixel Reference Value", "PIXEL_REFERENCE_VALUE"}, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq 07d", "PIXEL_REFERENCE_TYPE"}, + {NITF_BCS_N, 10, "Pixel Reference Value", "PIXEL_REFERENCE_VALUE"}, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq 07f", "PIXEL_REFERENCE_TYPE"}, + {NITF_BCS_N, 9, "Pixel Reference Value", "PIXEL_REFERENCE_VALUE"}, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq 07g", "PIXEL_REFERENCE_TYPE"}, + {NITF_BCS_N, 9, "Pixel Reference Value", "PIXEL_REFERENCE_VALUE"}, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq 07h", "PIXEL_REFERENCE_TYPE"}, + {NITF_BCS_N, 10, "Pixel Reference Value", "PIXEL_REFERENCE_VALUE"}, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq 08a", "PIXEL_REFERENCE_TYPE"}, + {NITF_BCS_N, 10, "Pixel Reference Value", "PIXEL_REFERENCE_VALUE"}, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq 08b", "PIXEL_REFERENCE_TYPE"}, + {NITF_BCS_N, 10, "Pixel Reference Value", "PIXEL_REFERENCE_VALUE"}, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq 08c", "PIXEL_REFERENCE_TYPE"}, + {NITF_BCS_N, 10, "Pixel Reference Value", "PIXEL_REFERENCE_VALUE"}, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq 08d", "PIXEL_REFERENCE_TYPE"}, + {NITF_BCS_N, 10, "Pixel Reference Value", "PIXEL_REFERENCE_VALUE"}, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq 08e", "PIXEL_REFERENCE_TYPE"}, + {NITF_BCS_N, 10, "Pixel Reference Value", "PIXEL_REFERENCE_VALUE"}, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq 08f", "PIXEL_REFERENCE_TYPE"}, + {NITF_BCS_N, 10, "Pixel Reference Value", "PIXEL_REFERENCE_VALUE"}, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq 08g", "PIXEL_REFERENCE_TYPE"}, + {NITF_BCS_N, 10, "Pixel Reference Value", "PIXEL_REFERENCE_VALUE"}, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq 08h", "PIXEL_REFERENCE_TYPE"}, + {NITF_BCS_N, 10, "Pixel Reference Value", "PIXEL_REFERENCE_VALUE"}, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq 08i", "PIXEL_REFERENCE_TYPE"}, + {NITF_BCS_N, 10, "Pixel Reference Value", "PIXEL_REFERENCE_VALUE"}, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq 09a", "PIXEL_REFERENCE_TYPE"}, + {NITF_BCS_N, 10, "Pixel Reference Value", "PIXEL_REFERENCE_VALUE"}, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq 09b", "PIXEL_REFERENCE_TYPE"}, + {NITF_BCS_N, 10, "Pixel Reference Value", "PIXEL_REFERENCE_VALUE"}, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq 09c", "PIXEL_REFERENCE_TYPE"}, + {NITF_BCS_N, 10, "Pixel Reference Value", "PIXEL_REFERENCE_VALUE"}, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq 09d", "PIXEL_REFERENCE_TYPE"}, + {NITF_BCS_N, 10, "Pixel Reference Value", "PIXEL_REFERENCE_VALUE"}, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq 10a", "PIXEL_REFERENCE_TYPE"}, + {NITF_BCS_N, 9, "Pixel Reference Value", "PIXEL_REFERENCE_VALUE"}, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq 10b", "PIXEL_REFERENCE_TYPE"}, + {NITF_BCS_N, 9, "Pixel Reference Value", "PIXEL_REFERENCE_VALUE"}, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq 10c", "PIXEL_REFERENCE_TYPE"}, + {NITF_BCS_N, 9, "Pixel Reference Value", "PIXEL_REFERENCE_VALUE"}, + {NITF_ENDIF, 0, NULL, NULL}, + /** End Pixel Referenced Data **/ + {NITF_ENDLOOP,0, NULL, NULL}, + {NITF_ENDLOOP,0, NULL, NULL}, + + {NITF_BCS_N, 3, "Uncertainty Data", "UNCERTAINTY_DATA"}, /* 14 */ + {NITF_LOOP, 0, NULL, "UNCERTAINTY_DATA"}, + {NITF_BCS_A, 11, "Uncertainty First Index", "UNCERTAINTY_FIRST_TYPE"}, /* 14a */ + {NITF_BCS_A, 11, "Uncertainty Second Index", "UNCERTAINTY_SECOND_TYPE"},/* 14b */ + {NITF_BCS_A, 10, "Uncertainty Value", "UNCERTAINTY_VALUE"}, /* 14c */ + {NITF_ENDLOOP,0, NULL, NULL}, + + {NITF_BCS_N, 3, "Additional Parameters", "ADDITIONAL_PARAMETER_DATA"},/* 15 */ + {NITF_LOOP, 0, NULL, "ADDITIONAL_PARAMETER_DATA"}, + {NITF_BCS_A, 25, "Parameter Name", "PARAMETER_NAME"}, /* 15a */ + {NITF_BCS_N, 3, "Parameter Field Size", "PARAMETER_SIZE"}, /* 15b */ + {NITF_BCS_N, 4, "Parameter Value Count", "PARAMETER_COUNT"}, /* 15c */ + {NITF_LOOP, 0, NULL, "PARAMETER_COUNT"}, + {NITF_BINARY,NITF_TRE_CONDITIONAL_LENGTH,"Parameter Value", + "PARAMETER_VALUE","PARAMETER_SIZE"}, /* 15d */ + {NITF_ENDLOOP,0, NULL, NULL}, + {NITF_ENDLOOP,0, NULL, NULL}, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(SENSRB, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/SNSPSB.c b/modules/c/nitf/shared/SNSPSB.c new file mode 100644 index 000000000..4290ea155 --- /dev/null +++ b/modules/c/nitf/shared/SNSPSB.c @@ -0,0 +1,91 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_N, 2, "Number of sets of sensor parameters", "NUMSNS" }, + {NITF_LOOP, 0, NULL, "NUMSNS"}, + {NITF_BCS_N, 2, "Number of Bounding Polygons", "NUM_BP" }, + {NITF_LOOP, 0, NULL, "NUM_BP"}, + {NITF_BCS_N, 2, "Number of Points in the Bounding Polygon", "NUM_PTS" }, + {NITF_LOOP, 0, NULL, "NUM_PTS"}, + {NITF_BCS_N, 15, "Longitude/Easting", "LON" }, + {NITF_BCS_N, 15, "Latitude/Northing", "LAT" }, + {NITF_ENDLOOP, 0, NULL, NULL}, + {NITF_ENDLOOP, 0, NULL, NULL}, + {NITF_BCS_N, 2, "Number of Bands", "NUM_BND" }, + {NITF_LOOP, 0, NULL, "NUM_BND"}, + {NITF_BCS_A, 5, "Original Scene Band Identification", "BID" }, + {NITF_BCS_N, 5, "Signal Lower Limit", "WS1" }, + {NITF_BCS_N, 5, "Signal Upper Limit", "WS2" }, + {NITF_ENDLOOP, 0, NULL, NULL}, + {NITF_BCS_A, 3, "Resolutions and ground sample distances units", "UNIRES" }, + {NITF_BCS_N, 6, "Resolution in columns", "REX" }, + {NITF_BCS_N, 6, "Resolution in rows", "REY" }, + {NITF_BCS_N, 6, "Ground Sample Distance in columns", "GSX" }, + {NITF_BCS_N, 6, "Ground Sample Distance in rows", "GSY" }, + {NITF_BCS_A, 12, "Location of pixel for GSX and GSY", "GSL" }, + {NITF_BCS_A, 8, "Vector or Mission Name", "PLTFM" }, + {NITF_BCS_A, 8, "Sensor or Instrument Name", "INS" }, + {NITF_BCS_A, 4, "Spectral Mode", "MOD" }, + {NITF_BCS_A, 5, "Processing Level", "PRL" }, + {NITF_BCS_A, 18, "Acquisition Date and Time", "ACT" }, + {NITF_BCS_A, 3, "Unit of the Scene Orientation Angle" , "UNINOA" }, + {NITF_BCS_N, 7, "Scene Orientation Angle", "NOA" }, + {NITF_BCS_A, 3, "Unit of Incidence Angle", "UNIANG" }, + {NITF_BCS_N, 7, "Incidence Angle at Original Scene Center", "ANG" }, + {NITF_BCS_A, 3, "Unit of Altitude", "UNIALT" }, + {NITF_BCS_N, 9, "Altitude of Sensor", "ALT" }, + {NITF_BCS_N, 10, "WGS84 Longitude of Original Scene Centre", "LONSCC" }, + {NITF_BCS_N, 10, "WGS84 Latitude of Original Scene Centre", "LATSCC" }, + {NITF_BCS_A, 3, "Unit of Solar Angles", "UNISAE" }, + {NITF_BCS_N, 7, "Solar Azimuth", "SAZ" }, + {NITF_BCS_N, 7, "Solar Elevation", "SEL" }, + {NITF_BCS_A, 3, "Unit of Attitude Angles", "UNIRPY" }, + {NITF_BCS_N, 7, "Roll of the Sensor", "ROL" }, + {NITF_BCS_N, 7, "Pitch of the Sensor", "PIT" }, + {NITF_BCS_N, 7, "Yaw of the Sensor", "YAW" }, + {NITF_BCS_A, 3, "Unit of Pixel Time", "UNIPXT" }, + {NITF_BCS_N, 14, "Pixel Time", "PIXT" }, + {NITF_BCS_A, 7, "Unit of Attitude Speed", "UNISPE" }, + {NITF_BCS_N, 22, "Roll Speed", "ROS" }, + {NITF_BCS_N, 22, "Pitch Speed", "PIS" }, + {NITF_BCS_N, 22, "Yaw Speed", "YAS" }, + {NITF_BCS_N, 3, "Number of Auxiliary Parameters", "NUM_AUX" }, + {NITF_LOOP, 0, NULL, "NUM_AUX"}, + {NITF_BCS_A, 20, "Auxiliary Parameter ID", "API" }, + {NITF_BCS_A, 1, "Auxiliary Parameter Value Format", "APF" }, + {NITF_BCS_A, 7, "Unit of Auxiliary Parameter", "UNIAPX" }, + {NITF_BCS_N, 10, "Auxiliary Parameter Integer Value", "APN" }, + {NITF_BCS_N, 20, "Auxiliary Parameter Real Value", "APR" }, + {NITF_BCS_A, 20, "Auxiliary Parameter Characters String Value", "APA" }, + {NITF_ENDLOOP, 0, NULL, NULL}, + {NITF_ENDLOOP, 0, NULL, NULL}, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(SNSPSB, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/SNSRA.c b/modules/c/nitf/shared/SNSRA.c new file mode 100644 index 000000000..d30877e95 --- /dev/null +++ b/modules/c/nitf/shared/SNSRA.c @@ -0,0 +1,112 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_N, 4, "VERNUM", "VERNUM" }, + {NITF_BCS_A, 20, "SENNAME", "SENNAME" }, + {NITF_BCS_A, 1, "SENTYPE", "SENTYPE" }, + {NITF_BCS_A, 10, "SENMODE", "SENMODE" }, + {NITF_BCS_A, 12, "SENSCAN", "SENSCAN" }, + {NITF_BCS_A, 10, "SENSOR_ID", "SENSOR_ID" }, + {NITF_BCS_A, 3, "MPLAN", "MPLAN" }, + {NITF_BCS_A, 4, "SENSERIAL", "SENSERIAL" }, + {NITF_BCS_A, 10, "SENOPORG", "SENOPORG" }, + {NITF_BCS_A, 12, "SENMFG", "SENMFG" }, + {NITF_BCS_A, 7, "ABSWVER", "ABSWVER" }, + {NITF_BCS_A, 5, "AVG_ALT", "AVG_ALT" }, + {NITF_IF, 0, "eq R", "SENTYPE"}, + {NITF_BCS_A, 7, "FOC_X", "FOC_X" }, + {NITF_BCS_A, 7, "FOC_Y", "FOC_Y" }, + {NITF_BCS_A, 7, "FOC_Z", "FOC_Z" }, + {NITF_BCS_N, 1, "NUM_SENBAND", "NUM_SENBAND" }, + {NITF_LOOP, 0, NULL, "NUM_SENBAND"}, + {NITF_BCS_A, 10, "SENBAND", "SENBAND" }, + {NITF_BCS_A, 3, "SEN_BANDW", "SEN_BANDWL" }, + {NITF_BCS_A, 3, "SEN_CEN_F", "SEN_CEN_F" }, + {NITF_BCS_A, 2, "POLARIZATION", "POLARIZATION" }, + {NITF_BCS_A, 6, "AZ_BWIDTH", "AZ_BWIDTH" }, + {NITF_BCS_A, 6, "EL_BWIDTH", "EL_BWIDTH" }, + {NITF_BCS_A, 4, "DYN_RNGE", "DYN_RNGE" }, + {NITF_BCS_A, 15, "SENCALFAC", "SENCALFAC" }, + {NITF_ENDLOOP, 0, NULL, NULL}, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq I", "SENTYPE"}, + {NITF_BCS_N, 1, "NUM_SENBAND", "NUM_SENBAND" }, + {NITF_LOOP, 0, NULL, "NUM_SENBAND"}, + {NITF_BCS_A, 10, "SENBAND", "SENBAND" }, + {NITF_BCS_A, 3, "SEN_FOV_T", "SEN_FOV_T" }, + {NITF_BCS_A, 1, "SEN_FOV_T_U", "SEN_FOV_T_U" }, + {NITF_BCS_A, 3, "SEN_IFOV_T", "SEN_IFOV_T" }, + {NITF_BCS_A, 1, "SEN_IFOV_T_U", "SEN_IFOV_T_U" }, + {NITF_BCS_A, 5, "SEN_FOV_CT", "SEN_FOV_CT" }, + {NITF_BCS_A, 3, "SEN_IFOV_CT", "SEN_IFOV_CT" }, + {NITF_BCS_A, 1, "SEN_IFOV_CT_U", "SEN_IFOV_CT_U" }, + {NITF_BCS_A, 3, "SEN_FOR_T", "SEN_FOR_T" }, + {NITF_BCS_A, 3, "SEN_FOR_CT", "SEN_FOR_CT" }, + {NITF_BCS_A, 4, "SEN_L_WAVE", "SEN_L_WAVE" }, + {NITF_BCS_A, 4, "SEN_U_WAVE", "SEN_U_WAVE" }, + {NITF_BCS_A, 3, "SUBBANDS", "SUBBANDS" }, + {NITF_BCS_A, 4, "SENFLENGTH", "SENFLENGTH" }, + {NITF_BCS_A, 4, "SENFNUM", "SENFNUM" }, + {NITF_BCS_A, 4, "LINESAMPLES", "LINESAMPLES" }, + {NITF_BCS_A, 12, "DETECTTYPE", "DETECTTYPE" }, + {NITF_BCS_A, 2, "POLARIZATION", "POLARIZATION" }, + {NITF_BCS_A, 4, "DYN_RNGE", "DYN_RNGE" }, + {NITF_BCS_A, 15, "SENCALFAC", "SENCALFAC" }, + {NITF_ENDLOOP, 0, NULL, NULL}, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_IF, 0, "eq E", "SENTYPE"}, + {NITF_BCS_N, 1, "NUM_SENBAND", "NUM_SENBAND" }, + {NITF_LOOP, 0, NULL, "NUM_SENBAND"}, + {NITF_BCS_A, 10, "SENBAND", "SENBAND" }, + {NITF_BCS_A, 3, "SEN_FOV_T", "SEN_FOV_T" }, + {NITF_BCS_A, 1, "SEN_FOV_T_U", "SEN_FOV_T_U" }, + {NITF_BCS_A, 3, "SEN_IFOV_T", "SEN_IFOV_T" }, + {NITF_BCS_A, 1, "SEN_IFOV_T_U", "SEN_IFOV_T_U" }, + {NITF_BCS_A, 5, "SEN_FOV_CT", "SEN_FOV_CT" }, + {NITF_BCS_A, 3, "SEN_IFOV_CT", "SEN_IFOV_CT" }, + {NITF_BCS_A, 1, "SEN_IFOV_CT_U", "SEN_IFOV_CT_U" }, + {NITF_BCS_A, 3, "SEN_FOR_T", "SEN_FOR_T" }, + {NITF_BCS_A, 3, "SEN_FOR_CT", "SEN_FOR_CT" }, + {NITF_BCS_A, 4, "SEN_L_WAVE", "SEN_L_WAVE" }, + {NITF_BCS_A, 4, "SEN_U_WAVE", "SEN_U_WAVE" }, + {NITF_BCS_A, 3, "SUBBANDS", "SUBBANDS" }, + {NITF_BCS_A, 4, "SENFLENGTH", "SENFLENGTH" }, + {NITF_BCS_A, 4, "SENFNUM", "SENFNUM" }, + {NITF_BCS_A, 4, "LINESAMPLES", "LINESAMPLES" }, + {NITF_BCS_A, 12, "DETECTTYPE", "DETECTTYPE" }, + {NITF_BCS_A, 2, "POLARIZATION", "POLARIZATION" }, + {NITF_BCS_A, 4, "DYN_RNGE", "DYN_RNGE" }, + {NITF_BCS_A, 15, "SENCALFAC", "SENCALFAC" }, + {NITF_ENDLOOP, 0, NULL, NULL}, + {NITF_ENDIF, 0, NULL, NULL}, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(SNSRA, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/SOURCB.c b/modules/c/nitf/shared/SOURCB.c new file mode 100644 index 000000000..dbb227db8 --- /dev/null +++ b/modules/c/nitf/shared/SOURCB.c @@ -0,0 +1,126 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_N, 9, "Image Segment Reciprocal Scale", "IS_SCA" }, + {NITF_BCS_A, 10, "Colout Patch ID", "CPATCH" }, + {NITF_BCS_N, 2, "Number of Source Descriptions", "NUM_SOUR" }, + {NITF_LOOP, 0, NULL, "NUM_SOUR"}, + {NITF_BCS_N, 2, "Number of Bounding Polygons", "NUM_BP" }, + {NITF_LOOP, 0, NULL, "NUM_BP"}, + {NITF_BCS_N, 3, "Number of Points in the Bounding Polygon", "NUM_PTS" }, + {NITF_LOOP, 0, NULL, "NUM_PTS"}, + {NITF_BCS_N, 15, "Longitude/Easting", "LON" }, + {NITF_BCS_N, 15, "Latitude/Northing", "LAT" }, + {NITF_ENDLOOP, 0, NULL, NULL}, + {NITF_ENDLOOP, 0, NULL, NULL}, + {NITF_BCS_A, 10, "Series", "PRT" }, + {NITF_BCS_A, 20, "Source Identification", "URF" }, + {NITF_BCS_A, 7, "Edition", "EDN" }, + {NITF_BCS_A, 20, "Name", "NAM" }, + {NITF_BCS_N, 3, "Type of Significant Date", "CDP" }, + {NITF_BCS_A, 8, "Significant Date", "CDV" }, + {NITF_BCS_A, 8, "Perishable Date", "CDV27" }, + {NITF_BCS_A, 80, "Source Reference Number", "SRN" }, + {NITF_BCS_A, 9, "Reciprocal Scale", "SCA" }, + {NITF_BCS_A, 3, "Unit of Measure for Coverage", "UNISQU" }, + {NITF_BCS_N, 10, "Coverage", "SQU" }, + {NITF_BCS_A, 3, "Unit of Measure for Contour Interval", "UNIPCI" }, + {NITF_BCS_N, 4, "Contour Interval", "PCI" }, + {NITF_BCS_N, 3, "Water Coverage", "WPC" }, + {NITF_BCS_N, 3, "Navigation System Type", "NST" }, + {NITF_BCS_A, 3, "Units of HKE", "UNIHKE" }, + {NITF_BCS_N, 6, "Highest Elevation", "HKE" }, + {NITF_BCS_N, 15, "Longitude/Easting of HKE", "LONHKE" }, + {NITF_BCS_N, 15, "Latitude/Northing of HKE", "LATHKE" }, + {NITF_BCS_A, 1, "Security Classification of Source", "QSS" }, + {NITF_BCS_A, 1, "Downgrading", "QOD" }, + {NITF_BCS_A, 8, "Downgrading Date", "CDV10" }, + {NITF_BCS_A, 80, "Releasibility", "QLE" }, + {NITF_BCS_A, 80, "Copyright Statement", "CPY" }, + {NITF_BCS_N, 2, "Number of Magnetic Information", "NMI" }, + {NITF_LOOP, 0, NULL, "NMI"}, + {NITF_BCS_A, 8, "Date of Magnetic Information", "CDV30" }, + {NITF_BCS_A, 3, "Units for Annual Rate of Change", "UNIRAT" }, + {NITF_BCS_N, 8, "Annual Rate of Change", "RAT" }, + {NITF_BCS_A, 3, "Units of GMA", "UNIGMA" }, + {NITF_BCS_N, 8, "GM Angle", "GMA" }, + {NITF_BCS_N, 15, "Longitude/Easting of GMA Reference Point", "LONGMA" }, + {NITF_BCS_N, 15, "Latitude/Northing of GMA Reference Point", "LATGMA" }, + {NITF_BCS_A, 3, "Units of GCA", "UNIGCA" }, + {NITF_BCS_N, 8, "Grid Convergence Angle", "GCA" }, + {NITF_ENDLOOP, 0, NULL, NULL}, + {NITF_BCS_N, 2, "Number of Legend Images", "NLI" }, + {NITF_LOOP, 0, NULL, "NLI"}, + {NITF_BCS_A, 10, "Legend ID", "BAD" }, + {NITF_ENDLOOP, 0, NULL, NULL}, + {NITF_BCS_A, 80, "Geodetic Datum Name", "DAG" }, + {NITF_BCS_A, 4, "Geodetic Datum Code", "DCD" }, + {NITF_BCS_A, 80, "Ellipsoid Name", "ELL" }, + {NITF_BCS_A, 3, "Ellipsoid Code", "ELC" }, + {NITF_BCS_A, 80, "Vertical Datum Reference", "DVR" }, + {NITF_BCS_A, 4, "Code of Vertical Reference", "VDCDVR" }, + {NITF_BCS_A, 80, "Sounding Datum Name", "SDA" }, + {NITF_BCS_A, 4, "Code for Sounding Datum", "VDCSDA" }, + {NITF_BCS_A, 80, "Projection Name", "PRN" }, + {NITF_BCS_A, 2, "Projection Code", "PCO" }, + {NITF_BCS_N, 1, "Number of Projection Parameters", "NUM_PRJ" }, + {NITF_LOOP, 0, NULL, "NUM_PRJ"}, + {NITF_BCS_N, 15, "Projection Parameter", "PRJ" }, + {NITF_ENDLOOP, 0, NULL, NULL}, + {NITF_BCS_N, 15, "Projection False X (Easting) Origin", "XOR" }, + {NITF_BCS_N, 15, "Projection False Y (Northing) Origin", "YOR" }, + {NITF_BCS_A, 3, "Grid Code", "GRD" }, + {NITF_BCS_A, 80, "Grid Description", "GRN" }, + {NITF_BCS_N, 4, "Grid Zone number", "ZNA" }, + {NITF_BCS_N, 2, "Number of Insets", "NIN" }, + {NITF_LOOP, 0, NULL, "NIN"}, + {NITF_BCS_A, 10, "Inset Identification", "INT" }, + {NITF_BCS_N, 9, "Reciprocal Scale of Inset", "INS_SCA" }, + {NITF_BCS_N, 15, "Absolute longitude of lower left corner", "NTL" }, + {NITF_BCS_N, 15, "Absolute latitude of lower left corner", "TTL" }, + {NITF_BCS_N, 15, "Absolute longitude of upper left corner", "NVL" }, + {NITF_BCS_N, 15, "Absolute latitude of upper left corner", "TVL" }, + {NITF_BCS_N, 15, "Absolute longitude of upper right corner", "NTR" }, + {NITF_BCS_N, 15, "Absolute latitude of upper right corner", "TTR" }, + {NITF_BCS_N, 15, "Absolute longitude of lower right corner", "NVR" }, + {NITF_BCS_N, 15, "Absolute latitude of lower right corner", "TVR" }, + {NITF_BCS_N, 15, "Relative longitude of lower left corner", "NRL" }, + {NITF_BCS_N, 15, "Relative latitude of lower left corner", "TRL" }, + {NITF_BCS_N, 15, "Relative longitude of upper left corner", "NSL" }, + {NITF_BCS_N, 15, "Relative latitude of upper left corner", "TSL" }, + {NITF_BCS_N, 15, "Relative longitude of upper right corner", "NRR" }, + {NITF_BCS_N, 15, "Relative latitude of upper right corner", "TRR" }, + {NITF_BCS_N, 15, "Relative longitude of lower right corner", "NSR" }, + {NITF_BCS_N, 15, "Relative latitude of lower right corner", "TSR" }, + {NITF_ENDLOOP, 0, NULL, NULL}, + {NITF_ENDLOOP, 0, NULL, NULL}, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(SOURCB, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/STDIDC.c b/modules/c/nitf/shared/STDIDC.c new file mode 100644 index 000000000..289496530 --- /dev/null +++ b/modules/c/nitf/shared/STDIDC.c @@ -0,0 +1,52 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_A, 14, "ACQ DATE", "ACQUISITION_DATE" }, + {NITF_BCS_A, 14, "MISSION", "MISSION" }, + {NITF_BCS_A, 2, "PASS", "PASS" }, + {NITF_BCS_A, 3, "OP NUM", "OP_NUM" }, + {NITF_BCS_A, 2, "START SEGMENT", "START_SEGMENT" }, + {NITF_BCS_A, 2, "REPRO NUM", "REPRO_NUM" }, + {NITF_BCS_A, 3, "REPLAY REGEN", "REPLAY_REGEN" }, + {NITF_BCS_A, 1, "BLANK FILL", "BLANK_FILL" }, + {NITF_BCS_A, 3, "START COLUMN", "START_COLUMN" }, + {NITF_BCS_A, 5, "START ROW", "START_ROW" }, + {NITF_BCS_A, 2, "END SEGMENT", "END_SEGMENT" }, + {NITF_BCS_A, 3, "END COLUMN", "END_COLUMN" }, + {NITF_BCS_A, 5, "END ROW", "END_ROW" }, + {NITF_BCS_A, 2, "COUNTRY", "COUNTRY" }, + {NITF_BCS_A, 4, "W A C", "WAC" }, + {NITF_BCS_A, 11, "LOCATION", "LOCATION" }, + {NITF_BCS_A, 5, "Reserved 1", "RESERV01" }, + {NITF_BCS_A, 8, "Reserved 2", "RESERV02" }, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(STDIDC, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/STEROB.c b/modules/c/nitf/shared/STEROB.c new file mode 100644 index 000000000..d616fe857 --- /dev/null +++ b/modules/c/nitf/shared/STEROB.c @@ -0,0 +1,43 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_A, 60, "Standard ID", "ST_ID" }, + {NITF_BCS_A, 1, "N Mates", "N_MATES" }, + {NITF_BCS_A, 1, "Mate Instance", "MATE_INSTANCE" }, + {NITF_BCS_A, 5, "B Conv", "B_CONV" }, + {NITF_BCS_A, 5, "E Conv", "E_CONV" }, + {NITF_BCS_A, 5, "B Asym", "B_ASYM" }, + {NITF_BCS_A, 5, "E Asym", "E_ASYM" }, + {NITF_BCS_A, 6, "B BIE", "B_BIE" }, + {NITF_BCS_A, 6, "E EIE", "E_EIE" }, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(STEROB, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/STREOB.c b/modules/c/nitf/shared/STREOB.c new file mode 100644 index 000000000..d028ee1f9 --- /dev/null +++ b/modules/c/nitf/shared/STREOB.c @@ -0,0 +1,43 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_A, 60, "Standard ID", "ST_ID" }, + {NITF_BCS_A, 1, "Nunber of Stereo Mates", "N_MATES" }, + {NITF_BCS_A, 1, "Mate Instance", "MATE_INSTANCE" }, + {NITF_BCS_A, 5, "Begining Convergence Angle", "B_CONV" }, + {NITF_BCS_A, 5, "Ending Convergence Angle", "E_CONV" }, + {NITF_BCS_A, 5, "Begining Asymmetric Angle", "B_ASYM" }, + {NITF_BCS_A, 5, "Ending Asymmetric Angle", "E_ASYM" }, + {NITF_BCS_A, 6, "Begining Bisector Intercept Elevation", "B_BIE" }, + {NITF_BCS_A, 6, "Ending Bisector Intercept Elevation", "E_BIE" }, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(STREOB, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/TEST_DES.c b/modules/c/nitf/shared/TEST_DES.c new file mode 100644 index 000000000..70dcaab8f --- /dev/null +++ b/modules/c/nitf/shared/TEST_DES.c @@ -0,0 +1,95 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + + +/* +* Simple example DES for testing. + + This file defines a very simple Data Extension Segment. This example is + used for test of the UserSegment object and can be used aa an example + and starting point for the development of DES. + + This example defines a "standard" DE segment which means the user + header can be implemented via a TRE object and there are no out of + segment dependencies + + The DES ID will be TEST_DES + + The user header will have three fields + + NITF_TEST_DES_COUNT - Number of data values + NITF_TEST_DES_START - Start value in ramp + NITF_TEST_DES_INCREMENT - Increment between values in ramp + + The data is an 8-bit ramp defined by the three values. in testing, the + ramp will be setup to contain printable values. + + This example includes a plug-in interface +*/ + +#include + +/* TRE access helper (-1 is returned on error) */ + + +/* TRE description for user header */ + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_N, 2, "Number of data values", "TEST_DES_COUNT" }, + {NITF_BCS_N, 3, "Start value in ramp", "TEST_DES_START" }, + {NITF_BCS_N, 2, "Increment between values in ramp", "TEST_DES_INCREMENT" }, + {NITF_END, 0, NULL, NULL} +}; + + +static const char *ident[] = +{ + NITF_PLUGIN_TRE_KEY, + "TEST DES", + "TEST_DES", + NULL +}; + +static nitf_TREDescriptionInfo descriptions[] = { + { "TEST DES", description, NITF_TRE_DESC_NO_LENGTH }, + { "TEST_DES", description, NITF_TRE_DESC_NO_LENGTH }, + { NULL, NULL, NITF_TRE_DESC_NO_LENGTH } +}; + +static nitf_TREDescriptionSet descriptionSet = { 0, descriptions }; +static nitf_TREHandler TEST_DESHandler; + +NITFAPI(const char**) TEST_DES_init(nitf_Error* error) +{ + if (!nitf_TREUtils_createBasicHandler(&descriptionSet, + &TEST_DESHandler,error)) + return NULL; + return ident; +} +NITFAPI(void) TEST_DES_cleanup(void){} +NITFAPI(nitf_TREHandler*) TEST_DES_handler(nitf_Error* error) { + return &TEST_DESHandler; +} + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/TRGTA.c b/modules/c/nitf/shared/TRGTA.c new file mode 100644 index 000000000..f609e4dd6 --- /dev/null +++ b/modules/c/nitf/shared/TRGTA.c @@ -0,0 +1,93 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + + +#include + +NITF_CXX_GUARD + + +static nitf_TREDescription description[] = { + {NITF_BCS_N, 4, "VERNUM", "VERNUM" }, + {NITF_BCS_N, 3, "NO_VALID_TGTS", "NO_VALID_TGTS" }, + {NITF_BCS_N, 3, "NO_SCENE_TGTS", "NO_SCENE_TGTS" }, + {NITF_LOOP, 0, NULL, "NO_VALID_TGTS"}, + {NITF_BCS_A, 25, "TGT_NAME", "TGT_NAME" }, + {NITF_BCS_A, 15, "TGT_TYPE", "TGT_TYPE" }, + {NITF_BCS_A, 6, "TGT_VER", "TGT_VER" }, + {NITF_BCS_A, 5, "TGT_CAT", "TGT_CAT" }, + {NITF_BCS_A, 17, "TGT_BE", "TGT_BE" }, + {NITF_BCS_A, 10, "TGT_SN", "TGT_SN" }, + {NITF_BCS_A, 2, "TGT_POSNUM", "TGT_POSNUM" }, + {NITF_BCS_A, 6, "TGT_ATTITUDE_PITCH", "TGT_ATTITUDE_PITCH" }, + {NITF_BCS_A, 6, "TGT_ATTITUDE_ROLL", "TGT_ATTITUDE_ROLL" }, + {NITF_BCS_A, 6, "TGT_ATTITUDE_YAW", "TGT_ATTITUDE_YAW" }, + {NITF_BCS_A, 5, "TGT_DIM_LENGTH", "TGT_DIM_LENGTH" }, + {NITF_BCS_A, 5, "TGT_DIM_WIDTH", "TGT_DIM_WIDTH" }, + {NITF_BCS_A, 5, "TGT_DIM_HEIGHT", "TGT_DIM_HEIGHT" }, + {NITF_BCS_A, 6, "TGT_AZIMUTH", "TGT_AZIMUTH" }, + {NITF_BCS_A, 8, "TGT_CLTR_RATIO", "TGT_CLTR_RATIO" }, + {NITF_BCS_A, 10, "TGT_STATE", "TGT_STATE" }, + {NITF_BCS_A, 30, "TGT_COND", "TGT_COND" }, + {NITF_BCS_A, 20, "TGT_OBSCR", "TGT_OBSCR" }, + {NITF_BCS_A, 3, "TGT_OBSCR%", "TGT_OBSCR%" }, + {NITF_BCS_A, 20, "TGT_CAMO", "TGT_CAMO" }, + {NITF_BCS_A, 3, "TGT_CAMO%", "TGT_CAMO%" }, + {NITF_BCS_A, 12, "TGT_UNDER", "TGT_UNDER" }, + {NITF_BCS_A, 30, "TGT_OVER", "TGT_OVER" }, + {NITF_BCS_A, 45, "TGT_TTEXTURE", "TGT_TTEXTURE" }, + {NITF_BCS_A, 40, "TGT_PAINT", "TGT_PAINT" }, + {NITF_BCS_A, 3, "TGT_SPEED", "TGT_SPEED" }, + {NITF_BCS_A, 3, "TGT_HEADING", "TGT_HEADING" }, + {NITF_BCS_N, 1, "TGT_QC_NUM", "TGT_QC_NUM" }, + {NITF_LOOP, 0, NULL, "TGT_QC_NUM"}, + {NITF_BCS_A, 40, "TGT_QCOMMENT", "TGT_QCOMMENT" }, + {NITF_ENDLOOP, 0, NULL, NULL}, + {NITF_BCS_N, 1, "TGT_CC_NUM", "TGT_CC_NUM" }, + {NITF_LOOP, 0, NULL, "TGT_CC_NUM"}, + {NITF_BCS_A, 40, "TGT_CCOMMENT", "TGT_CCOMMENT" }, + {NITF_ENDLOOP, 0, NULL, NULL}, + {NITF_BCS_N, 1, "NO_REF_PT", "NO_REF_PT" }, + {NITF_LOOP, 0, NULL, "NO_REF_PT"}, + {NITF_BCS_A, 10, "TGT_REF", "TGT_REF" }, + {NITF_BCS_A, 21, "TGT_LL", "TGT_LL" }, + {NITF_BCS_A, 8, "TGT_ELEV", "TGT_ELEV" }, + {NITF_BCS_A, 3, "TGT_BAND", "TGT_BAND" }, + {NITF_BCS_N, 8, "TGT_ROW", "TGT_ROW" }, + {NITF_BCS_N, 8, "TGT_COL", "TGT_COL" }, + {NITF_BCS_N, 8, "TGT_PROW", "TGT_PROW" }, + {NITF_BCS_N, 8, "TGT_PCOL", "TGT_PCOL" }, + {NITF_ENDLOOP, 0, NULL, NULL}, + {NITF_ENDLOOP, 0, NULL, NULL}, + {NITF_BCS_N, 3, "NO_ATTRIBUTES", "NO_ATTRIBUTES" }, + {NITF_LOOP, 0, NULL, "NO_ATTRIBUTES"}, + {NITF_BCS_N, 3, "ATTR_TGT_NUM", "ATTR_TGT_NUM" }, + {NITF_BCS_A, 30, "ATTR_NAME", "ATTR_NAME" }, + {NITF_BCS_A, 35, "ATTR_CONDTN", "ATTR_CONDTN" }, + {NITF_BCS_A, 10, "ATTR_VALUE", "ATTR_VALUE" }, + {NITF_ENDLOOP, 0, NULL, NULL}, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(TRGTA, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/USE00A.c b/modules/c/nitf/shared/USE00A.c new file mode 100644 index 000000000..c5278acc1 --- /dev/null +++ b/modules/c/nitf/shared/USE00A.c @@ -0,0 +1,58 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription description[] = { + {NITF_BCS_N, 3, "Angle to North", "ANGLE_TO_NORTH" }, + {NITF_BCS_A, 5, "Mean GSD ", "MEAN_GSD" }, + {NITF_BCS_A, 1, "Reserved 1", "rsrvd01" }, + {NITF_BCS_N, 5, "Dynamic Range", "DYNAMIC_RANGE" }, + {NITF_BCS_A, 3, "Reserved 2", "rsrvd02" }, + {NITF_BCS_A, 1, "Reserved 3", "rsrvd03" }, + {NITF_BCS_A, 3, "Reserved 4", "rsrvd04" }, + {NITF_BCS_A, 5, "Obliquity Angle", "OBL_ANG" }, + {NITF_BCS_A, 6, "Roll Angle", "ROLL_ANG" }, + {NITF_BCS_A, 12, "Reserved 5", "rsrvd05" }, + {NITF_BCS_A, 15, "Reserved 6", "rsrvd06" }, + {NITF_BCS_A, 4, "Reserved 7", "rsrvd07" }, + {NITF_BCS_A, 1, "Reserved 8", "rsrvd08" }, + {NITF_BCS_A, 3, "Reserved 9", "rsrvd09" }, + {NITF_BCS_A, 1, "Reserved 10", "rsrvd10" }, + {NITF_BCS_A, 1, "Reserved 11", "rsrvd11" }, + {NITF_BCS_N, 2, "Number of Reference Lines", "N_REF" }, + {NITF_BCS_N, 5, "Revolution Number", "REV_NUM" }, + {NITF_BCS_N, 3, "Number of Segments", "N_SEG" }, + {NITF_BCS_N, 6, "Max Lines per Segment", "MAX_LP_SEG" }, + {NITF_BCS_A, 6, "Reserved 12", "rsrvd12" }, + {NITF_BCS_A, 6, "Reserved 13", "rsrvd13" }, + {NITF_BCS_A, 5, "Sun Elevation", "SUN_EL" }, + {NITF_BCS_A, 5, "Sun Azimuth", "SUN_AZ" }, + {NITF_END, 0, NULL, NULL} +}; + +NITF_DECLARE_SINGLE_PLUGIN(USE00A, description) + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/XML_DATA_CONTENT.c b/modules/c/nitf/shared/XML_DATA_CONTENT.c new file mode 100644 index 000000000..aa06f94d4 --- /dev/null +++ b/modules/c/nitf/shared/XML_DATA_CONTENT.c @@ -0,0 +1,73 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + +NITF_CXX_GUARD + +static nitf_TREDescription descrip_0005[] = { + {NITF_BCS_N, 5, "Cyclic Redundancy Check", "DESCRC" }, + {NITF_END, 0, NULL, NULL} +}; + +static nitf_TREDescription descrip_0283[] = { + {NITF_BCS_N, 5, "Cyclic Redundancy Check", "DESCRC" }, + {NITF_BCS_A, 8, "XML File Type", "DESSHFT" }, + {NITF_BCS_A, 20, "Date and Time", "DESSHDT" }, + {NITF_BCS_A, 40, "Responsible Party Organization Identifier", "DESSHRP" }, + {NITF_BCS_A, 60, "Specification Identifier", "DESSHSI" }, + {NITF_BCS_A, 10, "Specification Version", "DESSHSV" }, + {NITF_BCS_A, 20, "Specification Date", "DESSHSD" }, + {NITF_BCS_A, 120, "Target Namespace", "DESSHTN" }, + {NITF_END, 0, NULL, NULL} +}; + +static nitf_TREDescription descrip_0773[] = { + {NITF_BCS_N, 5, "Cyclic Redundancy Check", "DESCRC" }, + {NITF_BCS_A, 8, "XML File Type", "DESSHFT" }, + {NITF_BCS_A, 20, "Date and Time", "DESSHDT" }, + {NITF_BCS_A, 40, "Responsible Party Organization Identifier", "DESSHRP" }, + {NITF_BCS_A, 60, "Specification Identifier", "DESSHSI" }, + {NITF_BCS_A, 10, "Specification Version", "DESSHSV" }, + {NITF_BCS_A, 20, "Specification Date", "DESSHSD" }, + {NITF_BCS_A, 120, "Target Namespace", "DESSHTN" }, + {NITF_BCS_A, 125, "Location Polygon", "DESSHLPG" }, + {NITF_BCS_A, 25, "Location Point", "DESSHLPT" }, + {NITF_BCS_A, 20, "Location Identifier", "DESSHLI" }, + {NITF_BCS_A, 120, "Location Identifier Namespace URI", "DESSHLIN" }, + {NITF_BCS_A, 200, "Abstract", "DESSHABS" }, + {NITF_END, 0, NULL, NULL} +}; + +/* Define the available descriptions and the default one */ +static nitf_TREDescriptionInfo descriptions[] = { + { "XML_DATA_CONTENT_005", descrip_0005, 5 }, + { "XML_DATA_CONTENT_283", descrip_0283, 283 }, + { "XML_DATA_CONTENT_773", descrip_0773, 773 }, + { NULL, NULL, NITF_TRE_DESC_NO_LENGTH } +}; +static nitf_TREDescriptionSet descriptionSet = { 0, descriptions }; + +NITF_DECLARE_PLUGIN(XML_DATA_CONTENT) + + +NITF_CXX_ENDGUARD diff --git a/modules/c/nitf/shared/wscript b/modules/c/nitf/shared/wscript new file mode 100644 index 000000000..a3fdf247e --- /dev/null +++ b/modules/c/nitf/shared/wscript @@ -0,0 +1,35 @@ +import os, subprocess +from waflib import Options +from os.path import splitext, dirname, join + +MAINTAINER = 'adam.sylvester@gd-ais.com' +VERSION = '1.0' +LANG = 'c' +USE = 'nitf-c' +PLUGIN = 'nitf' +REMOVEPLUGINPREFIX = True +DEFINES = ['NITF_MODULE_EXPORTS'] + +configure = options = distclean = lambda p: None + +def build(bld): + variant = bld.env['VARIANT'] or 'default' + env = bld.all_envs[variant] + + pluginList = [] + plugins = bld.path.ant_glob('*.c') + + for p in plugins: + filename = str(p) + + kw = globals() + pluginName = splitext(filename)[0] + kw['NAME'] = pluginName + kw['LIBNAME'] = pluginName + kw['SOURCE'] = filename + + bld.plugin(**kw) + pluginList.append(pluginName) + + bld(features='add_targets', target='nitro-plugins', + targets_to_add=pluginList) diff --git a/modules/c/nitf/source/BandInfo.c b/modules/c/nitf/source/BandInfo.c new file mode 100644 index 000000000..26224b838 --- /dev/null +++ b/modules/c/nitf/source/BandInfo.c @@ -0,0 +1,165 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/BandInfo.h" + +#define _NITF_CONSTRUCT_FIELD(OWNER, ID, TYPE) \ + OWNER->ID = nitf_Field_construct(ID##_SZ, TYPE, error); \ + if (!OWNER->ID) goto CATCH_ERROR; + +#define _NITF_CLONE_FIELD(DEST, SOURCE, ID) \ + DEST->ID = nitf_Field_clone(SOURCE->ID, error); \ + if (!DEST->ID) goto CATCH_ERROR; + +#define _NITF_DESTRUCT_FIELD(OWNER, ID) \ + if (OWNER->ID) nitf_Field_destruct(OWNER->ID); + +NITFAPI(nitf_BandInfo *) nitf_BandInfo_construct(nitf_Error * error) +{ + /* Start by allocating the struct */ + nitf_BandInfo *info = + (nitf_BandInfo *) NITF_MALLOC(sizeof(nitf_BandInfo)); + + /* Return now if we have a problem above */ + if (!info) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + return NULL; + } + + /* This MUST happen before we construct fields */ + /* in case destruction is required */ + info->lut = NULL; + + _NITF_CONSTRUCT_FIELD(info, NITF_IREPBAND, NITF_BCS_A); + _NITF_CONSTRUCT_FIELD(info, NITF_ISUBCAT, NITF_BCS_A); + _NITF_CONSTRUCT_FIELD(info, NITF_IFC, NITF_BCS_A); + _NITF_CONSTRUCT_FIELD(info, NITF_IMFLT, NITF_BCS_A); + _NITF_CONSTRUCT_FIELD(info, NITF_NLUTS, NITF_BCS_N); + _NITF_CONSTRUCT_FIELD(info, NITF_NELUT, NITF_BCS_N); + + return info; + +CATCH_ERROR: + /* destruct if it was allocated */ + if (info) + nitf_BandInfo_destruct(&info); + return NULL; +} + + +NITFAPI(void) nitf_BandInfo_destruct(nitf_BandInfo ** info) +{ + if (*info == NULL) + return; + + _NITF_DESTRUCT_FIELD(&(*info), NITF_IREPBAND); + _NITF_DESTRUCT_FIELD(&(*info), NITF_ISUBCAT); + _NITF_DESTRUCT_FIELD(&(*info), NITF_IFC); + _NITF_DESTRUCT_FIELD(&(*info), NITF_IMFLT); + _NITF_DESTRUCT_FIELD(&(*info), NITF_NLUTS); + _NITF_DESTRUCT_FIELD(&(*info), NITF_NELUT); + + if (&(*info)->lut) + { + nitf_LookupTable_destruct(&(*info)->lut); + } + + NITF_FREE(*info); + *info = NULL; +} + + +NITFPROT(nitf_BandInfo *) nitf_BandInfo_clone(nitf_BandInfo * source, + nitf_Error * error) +{ + /* Start with a NULL pointer */ + nitf_BandInfo *info = NULL; + if (source) + { + info = (nitf_BandInfo *) NITF_MALLOC(sizeof(nitf_BandInfo)); + if (!info) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + return NULL; + } + /* This must occur before cloning, in case an error */ + /* occurs and the object must be destructed */ + info->lut = NULL; + + _NITF_CLONE_FIELD(info, source, NITF_IREPBAND); + _NITF_CLONE_FIELD(info, source, NITF_ISUBCAT); + _NITF_CLONE_FIELD(info, source, NITF_IFC); + _NITF_CLONE_FIELD(info, source, NITF_IMFLT); + _NITF_CLONE_FIELD(info, source, NITF_NLUTS); + _NITF_CLONE_FIELD(info, source, NITF_NELUT); + + if (source->lut) + { + info->lut = nitf_LookupTable_clone(source->lut, error); + } + + return info; + } + +CATCH_ERROR: + return NULL; +} + + +NITFAPI(NITF_BOOL) nitf_BandInfo_init(nitf_BandInfo * bandInfo, + const char *representation, + const char *subcategory, + const char *imageFilterCondition, + const char *imageFilterCode, + nitf_Uint32 numLUTs, + nitf_Uint32 bandEntriesPerLUT, + nitf_LookupTable * lut, + nitf_Error * error) +{ + if (!nitf_Field_setString + (bandInfo->NITF_IREPBAND, representation, error)) + return (NITF_FAILURE); + + if (!nitf_Field_setString(bandInfo->NITF_ISUBCAT, subcategory, error)) + return (NITF_FAILURE); + + if (!nitf_Field_setString + (bandInfo->NITF_IFC, imageFilterCondition, error)) + return (NITF_FAILURE); + + if (!nitf_Field_setString + (bandInfo->NITF_IMFLT, imageFilterCode, error)) + return (NITF_FAILURE); + + if (!nitf_Field_setUint32(bandInfo->NITF_NLUTS, numLUTs, error)) + return (NITF_FAILURE); + + if (!nitf_Field_setUint32 + (bandInfo->NITF_NELUT, bandEntriesPerLUT, error)) + return (NITF_FAILURE); + + bandInfo->lut = lut; + return (NITF_SUCCESS); +} diff --git a/modules/c/nitf/source/BandSource.c b/modules/c/nitf/source/BandSource.c new file mode 100644 index 000000000..f01848c77 --- /dev/null +++ b/modules/c/nitf/source/BandSource.c @@ -0,0 +1,466 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/BandSource.h" + +/* + * Private implementation struct + */ +typedef struct _MemorySourceImpl +{ + char *data; + nitf_Off size; + nitf_Off mark; + int numBytesPerPixel; + int pixelSkip; + nitf_Off start; +} +MemorySourceImpl; + + +NITFPRIV(MemorySourceImpl *) toMemorySource(NITF_DATA * data, + nitf_Error * error) +{ + MemorySourceImpl *memorySource = (MemorySourceImpl *) data; + if (memorySource == NULL) + { + nitf_Error_init(error, "Null pointer reference", + NITF_CTXT, NITF_ERR_INVALID_OBJECT); + return NULL; + } + return memorySource; +} + + +NITFPRIV(NITF_BOOL) MemorySource_contigRead(MemorySourceImpl * + memorySource, char *buf, + nitf_Off size, + nitf_Error * error) +{ + memcpy(buf, + memorySource->data + memorySource->mark, + (size_t)size); + memorySource->mark += size; + return NITF_SUCCESS; +} + + +NITFPRIV(NITF_BOOL) MemorySource_offsetRead(MemorySourceImpl * + memorySource, char *buf, + nitf_Off size, + nitf_Error * error) +{ + int i = 0; + int j = 0; + + while (i < size) + { + for (j = 0; j < memorySource->numBytesPerPixel; ++j, ++i) + { + buf[i] = *(memorySource->data + memorySource->mark++); + } + memorySource->mark += + (memorySource->pixelSkip * memorySource->numBytesPerPixel); + } + return NITF_SUCCESS; +} + + +/* + * Private read implementation for memory source. + */ +NITFPRIV(NITF_BOOL) MemorySource_read(NITF_DATA * data, + char *buf, + nitf_Off size, nitf_Error * error) +{ + MemorySourceImpl *memorySource = toMemorySource(data, error); + if (!memorySource) + return NITF_FAILURE; + + /* We like the contiguous read case, its fast */ + /* We want to make sure we reward this case */ + if (memorySource->pixelSkip == 0) + return MemorySource_contigRead(memorySource, buf, size, error); + + return MemorySource_offsetRead(memorySource, buf, size, error); +} + + +NITFPRIV(void) MemorySource_destruct(NITF_DATA * data) +{ + MemorySourceImpl *memorySource = (MemorySourceImpl *) data; + if (memorySource) + NITF_FREE(memorySource); +} + + +NITFPRIV(nitf_Off) MemorySource_getSize(NITF_DATA * data, nitf_Error *e) +{ + MemorySourceImpl *memorySource = (MemorySourceImpl *) data; + return memorySource ? memorySource->size : 0; +} + +NITFPRIV(NITF_BOOL) MemorySource_setSize(NITF_DATA * data, nitf_Off size, nitf_Error *e) +{ + MemorySourceImpl *memorySource = (MemorySourceImpl *) data; + if (!memorySource) + { + nitf_Error_init(e, "Null pointer reference", + NITF_CTXT, NITF_ERR_INVALID_OBJECT); + return NITF_FAILURE; + } + memorySource->size = size; + return NITF_SUCCESS; +} + + + +NITFAPI(nitf_BandSource *) nitf_MemorySource_construct(char *data, + nitf_Off size, + nitf_Off start, + int numBytesPerPixel, + int pixelSkip, + nitf_Error * error) +{ + static nitf_IDataSource iMemorySource = + { + &MemorySource_read, + &MemorySource_destruct, + &MemorySource_getSize, + &MemorySource_setSize + }; + MemorySourceImpl *impl; + nitf_BandSource *bandSource; + + impl = (MemorySourceImpl *) NITF_MALLOC(sizeof(MemorySourceImpl)); + if (!impl) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), NITF_CTXT, + NITF_ERR_MEMORY); + return NULL; + } + + impl->data = data; + impl->size = size; + impl->numBytesPerPixel = numBytesPerPixel > 0 ? numBytesPerPixel : 1; + impl->mark = impl->start = (start >= 0 ? start : 0); + impl->pixelSkip = pixelSkip >= 0 ? pixelSkip : 0; + + bandSource = (nitf_BandSource *) NITF_MALLOC(sizeof(nitf_BandSource)); + if (!bandSource) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), NITF_CTXT, + NITF_ERR_MEMORY); + return NULL; + } + bandSource->data = impl; + bandSource->iface = &iMemorySource; + return bandSource; +} + + +/* + * Private implementation struct + */ +typedef struct _IOSourceImpl +{ + nitf_IOInterface *io; + nitf_Off start; + nitf_Off size; + int numBytesPerPixel; + int pixelSkip; + nitf_Off mark; +} +IOSourceImpl; + +NITFPRIV(void) IOSource_destruct(NITF_DATA * data) +{ + NITF_FREE(data); +} + +NITFPRIV(void) FileSource_destruct(NITF_DATA * data) +{ + if (data) + { + IOSourceImpl* const source = (IOSourceImpl*)data; + if (source->io) + { + nitf_IOInterface_destruct(&source->io); + } + NITF_FREE(data); + } +} + +NITFPRIV(nitf_Off) IOSource_getSize(NITF_DATA * data, nitf_Error *e) +{ + IOSourceImpl *source = (IOSourceImpl *) data; + return source ? (nitf_Off)source->size : 0; +} + + +NITFPRIV(NITF_BOOL) IOSource_setSize(NITF_DATA * data, nitf_Off size, nitf_Error *e) +{ + IOSourceImpl *source = (IOSourceImpl *) data; + if (!source) + { + nitf_Error_init(e, "Null pointer reference", + NITF_CTXT, NITF_ERR_INVALID_OBJECT); + return NITF_FAILURE; + } + source->size = size; + return NITF_SUCCESS; +} + + +NITFPRIV(IOSourceImpl *) toIOSource(NITF_DATA * data, nitf_Error *error) +{ + IOSourceImpl *source = (IOSourceImpl *) data; + if (source == NULL) + { + nitf_Error_init(error, "Null pointer reference", + NITF_CTXT, NITF_ERR_INVALID_OBJECT); + return NULL; + } + return source; +} + + +NITFPRIV(NITF_BOOL) IOSource_contigRead(IOSourceImpl * source, + char *buf, + nitf_Off size, + nitf_Error * error) +{ + if (!NITF_IO_SUCCESS(nitf_IOInterface_read(source->io, + buf, + (size_t)size, + error))) + return NITF_FAILURE; + source->mark += size; + return NITF_SUCCESS; + +} + + +/* + * The idea here is we will speed it up by creating a temporary buffer + * for reading from the io interface. Even with the allocation, this should + * be much faster than seeking every time. + * + * The basic idea is that we allocate the temporary buffer to the request + * size * the skip factor. It should be noted that the tradeoff here is that, + * for very large read values, this may be really undesirable, especially for + * large skip factors. + * + * If this proves to be a problem, I will revert it back to a seek/read paradigm + * -DP + */ +NITFPRIV(NITF_BOOL) IOSource_offsetRead(IOSourceImpl * source, + char *buf, + nitf_Off size, nitf_Error * error) +{ + + /* we do not multiply the pixelSkip by numBytesPerPixel, b/c this + * read method takes in size as number of bytes, not number of pixels */ + + /* TODO - this *could* be smaller, but this should be ok for now */ + nitf_Off tsize = size * (source->pixelSkip + 1); + + char *tbuf; + nitf_Off lmark = 0; + int i = 0; + int j = 0; + if (tsize + source->mark > source->size) + tsize = source->size - source->mark; + + tbuf = (char *) NITF_MALLOC((size_t)tsize); + if (!tbuf) + { + nitf_Error_init(error, + NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + return NITF_FAILURE; + } + + if (!nitf_IOInterface_read(source->io, tbuf, (size_t)tsize, error)) + { + NITF_FREE(tbuf); + return NITF_FAILURE; + } + /* Downsize for buf */ + while (i < size) + { + for (j = 0; j < source->numBytesPerPixel; ++j, ++i) + { + buf[i] = *(tbuf + lmark++); + } + lmark += (source->pixelSkip * source->numBytesPerPixel); + } + source->mark += lmark; + NITF_FREE(tbuf); + return NITF_SUCCESS; +} + + +/* + * Private read implementation for file source. + */ +NITFPRIV(NITF_BOOL) IOSource_read(NITF_DATA * data, + char *buf, + nitf_Off size, nitf_Error * error) +{ + IOSourceImpl *source = toIOSource(data, error); + if (!source) + return NITF_FAILURE; + + if (!NITF_IO_SUCCESS(nitf_IOInterface_seek(source->io, + source->mark, + NITF_SEEK_SET, error))) + return NITF_FAILURE; + if (source->pixelSkip == 0) + return IOSource_contigRead(source, buf, size, error); + return IOSource_offsetRead(source, buf, size, error); +} + + +NITFAPI(nitf_BandSource *) nitf_IOSource_construct(nitf_IOInterface *io, + nitf_Off start, + int numBytesPerPixel, + int pixelSkip, + nitf_Error * error) +{ + static nitf_IDataSource iIOSource = + { + &IOSource_read, + &IOSource_destruct, + &IOSource_getSize, + &IOSource_setSize + }; + IOSourceImpl *impl; + nitf_BandSource *bandSource; + + impl = (IOSourceImpl *) NITF_MALLOC(sizeof(IOSourceImpl)); + if (!impl) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), NITF_CTXT, + NITF_ERR_MEMORY); + return NULL; + } + impl->io = io; + impl->numBytesPerPixel = numBytesPerPixel > 0 ? numBytesPerPixel : 1; + impl->pixelSkip = pixelSkip >= 0 ? pixelSkip : 0; + impl->mark = impl->start = (start >= 0 ? start : 0); + impl->size = nitf_IOInterface_getSize(io, error); + + if (!NITF_IO_SUCCESS(impl->size)) + { + NITF_FREE(impl); + return NULL; + } + + bandSource = (nitf_BandSource *) NITF_MALLOC(sizeof(nitf_BandSource)); + if (!bandSource) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), NITF_CTXT, + NITF_ERR_MEMORY); + return NULL; + } + bandSource->data = impl; + bandSource->iface = &iIOSource; + return bandSource; +} + +NITFAPI(nitf_BandSource *) nitf_FileSource_construct(nitf_IOHandle handle, + nitf_Off start, + int numBytesPerPixel, + int pixelSkip, + nitf_Error * error) +{ + /* We need a way to free 'interface' when we destruct - the IOSource + * doesn't take ownership of it. + */ + static nitf_IDataSource iFileSource = + { + &IOSource_read, + &FileSource_destruct, + &IOSource_getSize, + &IOSource_setSize + }; + + nitf_IOInterface *interface = NULL; + nitf_BandSource* bandSource = NULL; + + interface = nitf_IOHandleAdapter_construct(handle, NRT_ACCESS_READONLY, + error); + if (interface == NULL) + { + return NULL; + } + + bandSource = nitf_IOSource_construct(interface, start, numBytesPerPixel, + pixelSkip, error); + if (bandSource == NULL) + { + return NULL; + } + + bandSource->iface = &iFileSource; + return bandSource; +} + +NITFAPI(nitf_BandSource *) nitf_FileSource_constructFile(const char* fname, + nitf_Off start, + int numBytesPerPixel, + int pixelSkip, + nitf_Error* error) +{ + /* We need a way to free 'interface' when we destruct - the IOSource + * doesn't take ownership of it. + */ + static nitf_IDataSource iFileSource = + { + &IOSource_read, + &FileSource_destruct, + &IOSource_getSize, + &IOSource_setSize + }; + + nitf_IOInterface* interface = NULL; + nitf_BandSource* bandSource = NULL; + + interface = nitf_IOHandleAdapter_open(fname, NRT_ACCESS_READONLY, + NRT_OPEN_EXISTING, error); + if (interface == NULL) + { + return NULL; + } + + bandSource = nitf_IOSource_construct(interface, start, numBytesPerPixel, + pixelSkip, error); + if (bandSource == NULL) + { + return NULL; + } + + bandSource->iface = &iFileSource; + return bandSource; +} + diff --git a/modules/c/nitf/source/ComplexityLevel.c b/modules/c/nitf/source/ComplexityLevel.c new file mode 100644 index 000000000..ecc7016ab --- /dev/null +++ b/modules/c/nitf/source/ComplexityLevel.c @@ -0,0 +1,668 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; + * If not, see . + * + */ + +#include "nitf/ComplexityLevel.h" + +typedef NITF_CLEVEL (*CLEVEL_CHECK_PTR)(nitf_Record*, nitf_Error*); + +/* Still need to handle CGM aggregate size check! */ +/* Still need to handle Text Size/seg Text Format Codes */ + + + +NITFPRIV(NITF_CLEVEL) checkILOC(nitf_ImageSubheader* subhdr, nitf_Error* error) +{ + char iloc[NITF_ILOC_SZ + 1]; + char num[6]; + int rowCoord, colCoord; + int lastRow, lastCol; + int nrows, ncols; + + if (!nitf_Field_get(subhdr->NITF_ILOC, iloc, + NITF_CONV_STRING, + NITF_ILOC_SZ + 1, error)) + return NITF_CLEVEL_CHECK_FAILED; + + num[5] = '\0'; + memcpy(num, iloc, 5); + rowCoord = atoi(num); + memcpy(num, &iloc[5], 5); + colCoord = atoi(num); + + if (!nitf_Field_get(subhdr->NITF_NROWS, &nrows, + NITF_CONV_INT, sizeof(int), error)) + return NITF_CLEVEL_CHECK_FAILED; + + if (!nitf_Field_get(subhdr->NITF_NCOLS, &ncols, + NITF_CONV_INT, sizeof(int), error)) + return NITF_CLEVEL_CHECK_FAILED; + + /* The Common Coordinate System Extent ranges are referring to the + * (inclusive) last row/col */ + lastRow = rowCoord + nrows - 1; + lastCol = colCoord + ncols - 1; + + if (lastRow <= 2047 && lastCol <= 2047) + return NITF_CLEVEL_03; + + if (lastRow <= 8191 && lastCol <= 8191) + return NITF_CLEVEL_05; + + if (lastRow <= 65535 && lastCol <= 65535) + return NITF_CLEVEL_06; + + if (lastRow <= 99999999 && lastCol <= 99999999) + return NITF_CLEVEL_07; + + return NITF_CLEVEL_09; +} + + +NITFPRIV(NITF_CLEVEL) checkCCSExtent(nitf_Record* record, + nitf_Error* error) +{ + int i = 0; + int clevel = NITF_CLEVEL_03; + nitf_ListIterator it = nitf_List_begin(record->images); + nitf_ListIterator end = nitf_List_end(record->images); + + while (nitf_ListIterator_notEqualTo(&it, &end)) + { + nitf_ImageSegment* imageSegment = + (nitf_ImageSegment*)nitf_ListIterator_get(&it); + + int result = checkILOC(imageSegment->subheader, error); + if (result == NITF_CLEVEL_CHECK_FAILED ) + return result; + + if ( result > clevel ) + { + clevel = result; + } + ++i; + nitf_ListIterator_increment(&it); + + } + return clevel; + +} + +NITFPRIV(NITF_CLEVEL) checkFileSize(nitf_Record* record, + nitf_Error* error) +{ + nitf_Int64 fl; + if (!nitf_Field_get(record->header->NITF_FL, &fl, NITF_CONV_INT, 8, error)) + return NITF_CLEVEL_CHECK_FAILED; + + if (fl <= 52428799) + return NITF_CLEVEL_03; + + if (fl <= 1073741823) + return NITF_CLEVEL_05; + + if (fl <= 2147483647) + return NITF_CLEVEL_06; + + if (fl <= NITF_INT64(10737418239)) + return NITF_CLEVEL_07; + + return NITF_CLEVEL_09; + +} + +NITFPRIV(NITF_CLEVEL) checkImage(nitf_ImageSubheader* subhdr, + nitf_Error* error) +{ + int nrows, ncols; + if (!nitf_Field_get(subhdr->NITF_NROWS, &nrows, NITF_CONV_INT, + sizeof(int), error)) + return NITF_CLEVEL_CHECK_FAILED; + + + if (!nitf_Field_get(subhdr->NITF_NCOLS, &ncols, NITF_CONV_INT, + sizeof(int), error)) + return NITF_CLEVEL_CHECK_FAILED; + + if (nrows <= 2048 && ncols <= 2048) + return NITF_CLEVEL_03; + + if (nrows <= 8192 && ncols <= 8192) + return NITF_CLEVEL_05; + + if (nrows <= 65536 && ncols <= 65536) + return NITF_CLEVEL_06; + + if (nrows <= 99999999 && ncols <= 99999999) + return NITF_CLEVEL_07; + + return NITF_CLEVEL_09; + +} + +NITFPRIV(NITF_CLEVEL) checkImageSize(nitf_Record* record, + nitf_Error* error) +{ + int clevel = NITF_CLEVEL_03; + + nitf_ListIterator it = nitf_List_begin(record->images); + nitf_ListIterator end = nitf_List_end(record->images); + + int i = 0; + + while (nitf_ListIterator_notEqualTo(&it, &end) ) + { + nitf_ImageSegment* imageSegment = + (nitf_ImageSegment*)nitf_ListIterator_get(&it); + int result = checkImage(imageSegment->subheader, error); + if ( result == NITF_CLEVEL_CHECK_FAILED ) return result; + + if ( result > clevel ) + { + clevel = result; + + } + ++i; + nitf_ListIterator_increment(&it); + } + return clevel; +} + +NITFPRIV(NITF_CLEVEL) checkImageBlock(nitf_ImageSubheader* subhdr, + nitf_Error* error) +{ + int nppbh, nppbv; + if (!nitf_Field_get(subhdr->NITF_NPPBH, &nppbh, NITF_CONV_INT, + sizeof(int), error)) + return NITF_CLEVEL_CHECK_FAILED; + + + if (!nitf_Field_get(subhdr->NITF_NPPBV, &nppbv, NITF_CONV_INT, + sizeof(int), error)) + return NITF_CLEVEL_CHECK_FAILED; + + if (nppbh <= 0 || nppbv <= 0) + return NITF_CLEVEL_09; + + if (nppbh <= 2048 && nppbv <= 2048) + return NITF_CLEVEL_03; + + if (nppbh <= 8192 && nppbv <= 8192) + return NITF_CLEVEL_05; + + return NITF_CLEVEL_06; + +} + +NITFPRIV(NITF_CLEVEL) checkBlockSize(nitf_Record* record, nitf_Error* error) +{ + int clevel = NITF_CLEVEL_03; + + nitf_ListIterator it = nitf_List_begin(record->images); + nitf_ListIterator end = nitf_List_end(record->images); + + int i = 0; + + while (nitf_ListIterator_notEqualTo(&it, &end) ) + { + nitf_ImageSegment* imageSegment = + (nitf_ImageSegment*)nitf_ListIterator_get(&it); + int result = checkImageBlock(imageSegment->subheader, error); + if ( result == NITF_CLEVEL_CHECK_FAILED ) return result; + + if ( result > clevel ) + { + clevel = result; + + } + ++i; + nitf_ListIterator_increment(&it); + } + return clevel; + + + +} + +NITFPRIV(NITF_CLEVEL) checkNumImages(nitf_Record* record, nitf_Error* error) +{ + nitf_Uint32 numi = nitf_Record_getNumImages(record, error); + return (numi > 20) ? NITF_CLEVEL_05 : NITF_CLEVEL_03; +} + +NITFPRIV(NITF_CLEVEL) checkNumDES(nitf_Record* record, nitf_Error* error) +{ + + int clevel = NITF_CLEVEL_03; + nitf_Uint32 numdes = nitf_Record_getNumDataExtensions(record, error); + + + if (numdes > 10) + { + + if (numdes <= 50) + clevel = NITF_CLEVEL_06; + + if (numdes <= 100) + clevel = NITF_CLEVEL_07; + + else + clevel = NITF_CLEVEL_09; + + } + return clevel; + +} + +NITFPRIV(NITF_CLEVEL) checkRGBImage(nitf_ImageSubheader* subhdr, + nitf_Error* error) +{ + int clevel = NITF_CLEVEL_03; + int nbands, nbpp; + char imode = subhdr->imageMode->raw[0]; + if (!nitf_Field_get(subhdr->NITF_NBANDS, &nbands, NITF_CONV_INT, + sizeof(int), error)) + { + return NITF_CLEVEL_CHECK_FAILED; + } + + if (!nitf_Field_get(subhdr->NITF_NBPP, &nbpp, NITF_CONV_INT, + sizeof(int), error)) + { + return NITF_CLEVEL_CHECK_FAILED; + } + + if ((memcmp(subhdr->NITF_IC->raw, "C8", 2) == 0 || + memcmp(subhdr->NITF_IC->raw, "M8", 2) == 0) && + nbpp > 32) + { + clevel = NITF_CLEVEL_09; + } + + if ((memcmp(subhdr->NITF_IC->raw, "C3", 2) == 0 || + memcmp(subhdr->NITF_IC->raw, "M3", 2) == 0) && + (nbpp > 8 || imode != 'P')) + { + clevel = NITF_CLEVEL_09; + } + + if (nbands != 3) + { + clevel = NITF_CLEVEL_09; + } + else if (imode != 'B' && + imode != 'P' && + imode != 'S' && + imode != 'R') + { + clevel = NITF_CLEVEL_09; + } + else + { + if (nbpp == 16 || nbpp == 32) + { + if (clevel < NITF_CLEVEL_06) + { + clevel = NITF_CLEVEL_06; + } + } + else if (nbpp != 8) + { + clevel = NITF_CLEVEL_09; + } + } + + return clevel; +} + +NITFPRIV(NITF_CLEVEL) checkRGBLUTImage(nitf_ImageSubheader* subhdr, + nitf_Error* error) +{ + int clevel = NITF_CLEVEL_03; + int nbands, nbpp; + char imode = subhdr->imageMode->raw[0]; + + if (!nitf_Field_get(subhdr->NITF_NBANDS, &nbands, NITF_CONV_INT, + sizeof(int), error)) + return NITF_CLEVEL_CHECK_FAILED; + + if (!nitf_Field_get(subhdr->NITF_NBPP, &nbpp, NITF_CONV_INT, + sizeof(int), error)) + return NITF_CLEVEL_CHECK_FAILED; + + if (memcmp(subhdr->NITF_IC->raw, "NC", 2) != 0 && + memcmp(subhdr->NITF_IC->raw, "NM", 2) != 0) + clevel = NITF_CLEVEL_09; + + if (nbands != 1) + { + clevel = NITF_CLEVEL_09; + } + else if (nbpp != 1 && nbpp != 8) + { + clevel = NITF_CLEVEL_09; + } + else if (imode != 'B') + { + clevel = NITF_CLEVEL_09; + } + return clevel; + +} + +NITFPRIV(NITF_CLEVEL) checkMonoImage(nitf_ImageSubheader* subhdr, + nitf_Error* error) +{ + int clevel = NITF_CLEVEL_03; + int nbands, nbpp; + char imode = subhdr->imageMode->raw[0]; + + if (!nitf_Field_get(subhdr->NITF_NBANDS, &nbands, NITF_CONV_INT, + sizeof(int), error)) + return NITF_CLEVEL_CHECK_FAILED; + + if (!nitf_Field_get(subhdr->NITF_NBPP, &nbpp, NITF_CONV_INT, + sizeof(int), error)) + return NITF_CLEVEL_CHECK_FAILED; + + if ( (memcmp(subhdr->NITF_IC->raw, "C3", 2) == 0) || + (memcmp(subhdr->NITF_IC->raw, "M3", 2) == 0) ) + { + if (nbpp != 8 && nbpp != 12) + clevel = NITF_CLEVEL_09; + } + + if (nbands != 1) + { + clevel = NITF_CLEVEL_09; + } + else if (nbpp != 1 && + nbpp != 8 && + nbpp != 12 && + nbpp != 16 && + nbpp != 32 && + nbpp != 64) + { + clevel = NITF_CLEVEL_09; + } + else if (imode != 'B') + { + clevel = NITF_CLEVEL_09; + } + return clevel; +} + +/* This is an optional feature */ +/* NITFPRIV(NITF_CLEVEL) checkNoDisplay(nitf_ImageSubheader* subhdr, */ +/* nitf_Error* error) */ +/* { */ +/* /\* Is it elevation data? *\/ */ + +/* /\* Is it location grid? *\/ */ + +/* /\* Is it matrix data? *\/ */ + + + +/* } */ + +NITFPRIV(NITF_CLEVEL) checkMultiImage(nitf_ImageSubheader* subhdr, + nitf_Error* error) +{ + int clevel = NITF_CLEVEL_03; + int nbands, nbpp; + char imode = subhdr->imageMode->raw[0]; + + if (!nitf_Field_get(subhdr->NITF_NBANDS, &nbands, NITF_CONV_INT, + sizeof(int), error)) + return NITF_CLEVEL_CHECK_FAILED; + + if (!nitf_Field_get(subhdr->NITF_NBPP, &nbpp, NITF_CONV_INT, + sizeof(int), error)) + return NITF_CLEVEL_CHECK_FAILED; + + /* Note that the rest of this check is covered below */ + if (memcmp(subhdr->NITF_IC->raw, "C8", 2) == 0 || + memcmp(subhdr->NITF_IC->raw, "M8", 2) == 0) + { + if (imode == 'B' || nbpp > 32) + clevel = NITF_CLEVEL_09; + + } + /* Normal JPEG */ + else if (memcmp(subhdr->NITF_IC->raw, "C3", 2) == 0 || + memcmp(subhdr->NITF_IC->raw, "M3", 2) == 0) + { + if (nbpp != 8 && nbpp != 12) + return NITF_CLEVEL_09; + } + + if (nbands < 2) + { + clevel = NITF_CLEVEL_09; + } + else if (nbands < 10) + { + if (clevel < NITF_CLEVEL_03) + clevel = NITF_CLEVEL_03; + } + else + { + if (nbands <= 255) + { + if (clevel < NITF_CLEVEL_06) + clevel = NITF_CLEVEL_06; + } + else if (nbands <= 999) + { + if (clevel < NITF_CLEVEL_07) + clevel = NITF_CLEVEL_07; + } + else clevel = NITF_CLEVEL_09; + + + } + + if (nbpp != 8 && + nbpp != 16 && + nbpp != 32 && + nbpp != 64) + { + + clevel = NITF_CLEVEL_09; + } + else if (imode != 'B') + { + clevel = NITF_CLEVEL_09; + } + return clevel; +} + + + +NITFPRIV(NITF_CLEVEL) checkSpecificImageAttributes(nitf_Record* record, + nitf_Error* error) +{ + NITF_CLEVEL clevel = NITF_CLEVEL_03; + + + nitf_ListIterator it = nitf_List_begin(record->images); + nitf_ListIterator end = nitf_List_end(record->images); + + int i = 0; + + while (nitf_ListIterator_notEqualTo(&it, &end) ) + { + + NITF_CLEVEL result = NITF_CLEVEL_UNKNOWN; + char irep[ NITF_IREP_SZ + 1]; + + nitf_ImageSegment* imageSegment = + (nitf_ImageSegment*)nitf_ListIterator_get(&it); + + if (!nitf_Field_get(imageSegment->subheader->NITF_IREP, + irep, NITF_CONV_STRING, + NITF_IREP_SZ + 1, error)) + return NITF_CLEVEL_CHECK_FAILED; + nitf_Utils_trimString(irep); + + if (strcmp( irep, "MONO") == 0) + { + + result = checkMonoImage(imageSegment->subheader, error); + } + else if (strcmp( irep, "RGB") == 0) + { + result = checkRGBImage(imageSegment->subheader, error); + } + else if (strcmp( irep, "RGB/LUT" ) == 0) + { + result = checkRGBLUTImage(imageSegment->subheader, error); + } + else if (strcmp( irep, "MULTI" ) == 0) + { + result = checkMultiImage(imageSegment->subheader, error); + } + else + { + /* What happens for these other reps ? */ + return result; + + } + + if ( result == NITF_CLEVEL_CHECK_FAILED ) return result; + + if ( result > clevel ) + { + clevel = result; + + } + ++i; + nitf_ListIterator_increment(&it); + } + return clevel; +} + +typedef struct _ComplexityLevelCheck +{ + CLEVEL_CHECK_PTR check; +} ComplexityLevelCheck; + +static ComplexityLevelCheck checks[] = +{ + { checkCCSExtent }, + { checkFileSize }, + { checkImageSize }, + { checkBlockSize }, + { checkNumImages }, + { checkNumDES }, + { checkSpecificImageAttributes }, + { NULL } +}; + +NITFAPI(NITF_CLEVEL) nitf_ComplexityLevel_measure(nitf_Record* record, + nitf_Error* error) +{ + /*char *p = checks[0].checkName;*/ + CLEVEL_CHECK_PTR checkToRun = checks[0].check; + NITF_CLEVEL clevel = NITF_CLEVEL_UNKNOWN; + int i = 0; + while ( checkToRun != NULL ) + { + NITF_CLEVEL checkComplexity = (*checkToRun)(record, error); + if (checkComplexity == NITF_CLEVEL_CHECK_FAILED) + { + return NITF_CLEVEL_CHECK_FAILED; + } + if (checkComplexity > clevel) + { + clevel = checkComplexity; + } + checkToRun = checks[++i].check; + } + return clevel; +} + + +NITFAPI(NITF_CLEVEL) nitf_ComplexityLevel_get(nitf_Record* record) +{ + + char* c2 = record->header->NITF_CLEVEL->raw; + + if (memcmp(c2, "03", 2) == 0) + return NITF_CLEVEL_03; + if (memcmp(c2, "05", 2) == 0) + return NITF_CLEVEL_05; + if (memcmp(c2, "06", 2) == 0) + return NITF_CLEVEL_06; + if (memcmp(c2, "07", 2) == 0) + return NITF_CLEVEL_07; + if (memcmp(c2, "09", 2) == 0) + return NITF_CLEVEL_09; + else return NITF_CLEVEL_UNKNOWN; + + +} + + +NITFAPI(NITF_BOOL) nitf_ComplexityLevel_toString(NITF_CLEVEL clevel, + char* c2) +{ + + NITF_BOOL success = NITF_FAILURE; + switch (clevel) + { + case NITF_CLEVEL_CHECK_FAILED: + break; + + case NITF_CLEVEL_03: + memcpy(c2, "03", 2); + success = NITF_SUCCESS; + break; + + case NITF_CLEVEL_05: + memcpy(c2, "05", 2); + success = NITF_SUCCESS; + break; + + case NITF_CLEVEL_06: + memcpy(c2, "06", 2); + success = NITF_SUCCESS; + break; + + + case NITF_CLEVEL_07: + memcpy(c2, "07", 2); + success = NITF_SUCCESS; + break; + + + case NITF_CLEVEL_09: + success = NITF_SUCCESS; + /* Dont break, we want 09 */ + + case NITF_CLEVEL_UNKNOWN: + memcpy(c2, "09", 2); + break; + + } + return success; +} diff --git a/modules/c/nitf/source/ComponentInfo.c b/modules/c/nitf/source/ComponentInfo.c new file mode 100644 index 000000000..c938f7d26 --- /dev/null +++ b/modules/c/nitf/source/ComponentInfo.c @@ -0,0 +1,101 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/ComponentInfo.h" + +#define _NITF_DESTRUCT_FIELD(OWNER, ID) \ + if (OWNER->ID) nitf_Field_destruct(OWNER->ID); + +/* Create the image info structure */ +NITFAPI(nitf_ComponentInfo *) nitf_ComponentInfo_construct(nitf_Uint32 + subheaderFieldWidth, + nitf_Uint32 + dataFieldWidth, + nitf_Error * + error) +{ + nitf_ComponentInfo *info = + (nitf_ComponentInfo *) NITF_MALLOC(sizeof(nitf_ComponentInfo)); + if (!info) + { + nitf_Error_init(error, + NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + return NULL; + } + /* Zero-init these fields */ + info->lengthSubheader = + nitf_Field_construct(subheaderFieldWidth, NITF_BCS_N, error); + if (!info->lengthSubheader) + goto CATCH_ERROR; + + info->lengthData = + nitf_Field_construct(dataFieldWidth, NITF_BCS_N, error); + if (!info->lengthData) + goto CATCH_ERROR; + /* Return the object */ + return info; + +CATCH_ERROR: + return NULL; +} + + +NITFAPI(nitf_ComponentInfo *) +nitf_ComponentInfo_clone(nitf_ComponentInfo * source, nitf_Error * error) +{ + nitf_ComponentInfo *info = NULL; + if (source) + { + info = + nitf_ComponentInfo_construct(source->lengthSubheader->length, + source->lengthData->length, + error); + if (!info) + goto CATCH_ERROR; + } + else + { + nitf_Error_initf(error, + NITF_CTXT, + NITF_ERR_INVALID_OBJECT, + "Trying to clone NULL pointer"); + } + return info; + +CATCH_ERROR: + return NULL; +} + + +/* Destroy the image info structure */ +NITFAPI(void) nitf_ComponentInfo_destruct(nitf_ComponentInfo ** info) +{ + if (!*info) + return; + + _NITF_DESTRUCT_FIELD(&(*info), lengthSubheader); + _NITF_DESTRUCT_FIELD(&(*info), lengthData); + + NITF_FREE(*info); + *info = NULL; +} diff --git a/modules/c/nitf/source/DESegment.c b/modules/c/nitf/source/DESegment.c new file mode 100644 index 000000000..54f75fe83 --- /dev/null +++ b/modules/c/nitf/source/DESegment.c @@ -0,0 +1,112 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/DESegment.h" + +NITFAPI(nitf_DESegment *) nitf_DESegment_construct(nitf_Error * error) +{ + nitf_DESegment *segment = + (nitf_DESegment *) NITF_MALLOC(sizeof(nitf_DESegment)); + + if (!segment) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + return NULL; + } + + /* The offset in the file */ + segment->offset = 0; + /* The end (offset + length) */ + segment->end = 0; + + /* This object gets created NOW */ + segment->subheader = NULL; + segment->subheader = nitf_DESubheader_construct(error); + if (!segment->subheader) + { + nitf_DESegment_destruct(&segment); + return NULL; + } + + /* Yes! We have a success */ + return segment; +} + + +NITFAPI(nitf_DESegment *) nitf_DESegment_clone(nitf_DESegment * source, + nitf_Error * error) +{ + nitf_DESegment *segment = NULL; + + if (source) + { + segment = (nitf_DESegment *) NITF_MALLOC(sizeof(nitf_DESegment)); + + if (!segment) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + return NULL; + } + /* The offset in the file */ + segment->offset = source->offset; + /* The end (offset + length) */ + segment->end = source->end; + + /* Just in case we self-destruct */ + segment->subheader = NULL; + segment->subheader = + nitf_DESubheader_clone(source->subheader, error); + if (!segment->subheader) + { + nitf_DESegment_destruct(&segment); + return NULL; + } + } + else + { + nitf_Error_initf(error, + NITF_CTXT, + NITF_ERR_INVALID_OBJECT, + "Trying to clone NULL pointer"); + } + /* Yes! We have a success */ + return segment; +} + + +NITFAPI(void) nitf_DESegment_destruct(nitf_DESegment ** segment) +{ + if (*segment) + { + if ((*segment)->subheader) + { + /* Destroy subheader info */ + nitf_DESubheader_destruct(&(*segment)->subheader); + } + + NITF_FREE(*segment); + *segment = NULL; + + } +} diff --git a/modules/c/nitf/source/DESubheader.c b/modules/c/nitf/source/DESubheader.c new file mode 100644 index 000000000..b7bb6f919 --- /dev/null +++ b/modules/c/nitf/source/DESubheader.c @@ -0,0 +1,188 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/DESubheader.h" + +#define _NITF_CONSTRUCT_FIELD(OWNER, ID, TYPE) \ + OWNER->ID = nitf_Field_construct(ID##_SZ, TYPE, error); \ + if (!OWNER->ID) goto CATCH_ERROR; + +#define _NITF_CLONE_FIELD(DEST, SOURCE, ID) \ + DEST->ID = nitf_Field_clone(SOURCE->ID, error); \ + if (!DEST->ID) goto CATCH_ERROR; + +#define _NITF_DESTRUCT_FIELD(OWNER, ID) \ + if (OWNER->ID) nitf_Field_destruct(OWNER->ID); + +NITFAPI(nitf_DESubheader *) nitf_DESubheader_construct(nitf_Error * error) +{ + /* Start by allocating the header */ + nitf_DESubheader *subhdr = (nitf_DESubheader *) + NITF_MALLOC(sizeof(nitf_DESubheader)); + + /* Return now if we have a problem above */ + if (!subhdr) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + return NULL; + } + /* Need to set all of these before destructor could be + safely called - DP */ + + subhdr->securityGroup = NULL; + subhdr->subheaderFields = NULL; + subhdr->dataLength = 0; + subhdr->userDefinedSection = NULL; + + subhdr->securityGroup = nitf_FileSecurity_construct(error); + if (!subhdr->securityGroup) + { + nitf_DESubheader_destruct(&subhdr); + goto CATCH_ERROR; + } + + _NITF_CONSTRUCT_FIELD(subhdr, NITF_DE, NITF_BCS_A); + _NITF_CONSTRUCT_FIELD(subhdr, NITF_DESTAG, NITF_BCS_A); + _NITF_CONSTRUCT_FIELD(subhdr, NITF_DESVER, NITF_BCS_N); + _NITF_CONSTRUCT_FIELD(subhdr, NITF_DESCLAS, NITF_BCS_A); + + _NITF_CONSTRUCT_FIELD(subhdr, NITF_DESOFLW, NITF_BCS_A); + _NITF_CONSTRUCT_FIELD(subhdr, NITF_DESITEM, NITF_BCS_N); + + _NITF_CONSTRUCT_FIELD(subhdr, NITF_DESSHL, NITF_BCS_N); + + subhdr->userDefinedSection = nitf_Extensions_construct(error); + if (!subhdr->userDefinedSection) + goto CATCH_ERROR; + + return subhdr; + +CATCH_ERROR: + nitf_DESubheader_destruct(&subhdr); + return NULL; +} + + +NITFAPI(nitf_DESubheader *) +nitf_DESubheader_clone(nitf_DESubheader * source, nitf_Error * error) +{ + nitf_Uint32 subLen; + nitf_DESubheader *subhdr = NULL; + NITF_BOOL success; + if (source) + { + subhdr = + (nitf_DESubheader *) NITF_MALLOC(sizeof(nitf_DESubheader)); + if (!subhdr) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + return NULL; + } + + subhdr->securityGroup = + nitf_FileSecurity_clone(source->securityGroup, error); + if (!subhdr->securityGroup) + goto CATCH_ERROR; + + /* Copy some fields */ + _NITF_CLONE_FIELD(subhdr, source, NITF_DE); + _NITF_CLONE_FIELD(subhdr, source, NITF_DESTAG); + _NITF_CLONE_FIELD(subhdr, source, NITF_DESVER); + _NITF_CLONE_FIELD(subhdr, source, NITF_DESCLAS); + _NITF_CLONE_FIELD(subhdr, source, NITF_DESOFLW); + _NITF_CLONE_FIELD(subhdr, source, NITF_DESITEM); + + /* And some ints */ + _NITF_CLONE_FIELD(subhdr, source, NITF_DESSHL); + subhdr->dataLength = source->dataLength; + + success = nitf_Field_get(source->subheaderFieldsLength, &subLen, + NITF_CONV_INT, sizeof(subLen), error); + if (!success) + { + goto CATCH_ERROR; + } + + subhdr->subheaderFields = NULL; + subhdr->userDefinedSection = NULL; + + if (source->subheaderFields) + { + subhdr->subheaderFields = + nitf_TRE_clone(source->subheaderFields, error); + if (!subhdr->subheaderFields) + { + goto CATCH_ERROR; + } + } + if (source->userDefinedSection) + { + subhdr->userDefinedSection = + nitf_Extensions_clone(source->userDefinedSection, error); + + if (!subhdr->userDefinedSection) + { + goto CATCH_ERROR; + } + } + + return subhdr; + } + +CATCH_ERROR: + nitf_DESubheader_destruct(&subhdr); + return NULL; +} + + +NITFAPI(void) nitf_DESubheader_destruct(nitf_DESubheader ** subhdr) +{ + if (!*subhdr) + return; + + if ((*subhdr)->userDefinedSection) + { + nitf_Extensions_destruct(&(*subhdr)->userDefinedSection); + } + if ((*subhdr)->securityGroup) + { + nitf_FileSecurity_destruct(&(*subhdr)->securityGroup); + (*subhdr)->securityGroup = NULL; + } + if ((*subhdr)->subheaderFields) + { + nitf_TRE_destruct(&(*subhdr)->subheaderFields); + } + + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_DE); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_DESTAG); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_DESVER); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_DESCLAS); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_DESOFLW); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_DESITEM); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_DESSHL); + + NITF_FREE(*subhdr); + *subhdr = NULL; +} diff --git a/modules/c/nitf/source/DataSource.c b/modules/c/nitf/source/DataSource.c new file mode 100644 index 000000000..adc468748 --- /dev/null +++ b/modules/c/nitf/source/DataSource.c @@ -0,0 +1,35 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/DataSource.h" + + +NITFAPI(void) nitf_DataSource_destruct(nitf_DataSource ** dataSource) +{ + if (*dataSource) + { + if ((*dataSource)->iface) + (*dataSource)->iface->destruct((*dataSource)->data); + NITF_FREE(*dataSource); + *dataSource = NULL; + } +} diff --git a/modules/c/nitf/source/DefaultTRE.c b/modules/c/nitf/source/DefaultTRE.c new file mode 100644 index 000000000..e9ee389f9 --- /dev/null +++ b/modules/c/nitf/source/DefaultTRE.c @@ -0,0 +1,415 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/DefaultTRE.h" +#include "nitf/TREPrivateData.h" + +#define _NITF_DEFAULT_TRE_LABEL "Unknown raw data" + +NITFPRIV(NITF_BOOL) defaultInit(nitf_TRE* tre, const char* id, nitf_Error * error) +{ + nitf_TREDescription* descr; + + /* create a new private data struct */ + tre->priv = nitf_TREPrivateData_construct(error); + if (!tre->priv) + return NITF_FAILURE; + + + descr = + (nitf_TREDescription *) NITF_MALLOC(2 * + sizeof(nitf_TREDescription)); + if (!descr) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + return NITF_FAILURE; + } + + descr[0].data_type = NITF_BINARY; + descr[0].data_count = NITF_TRE_GOBBLE; + descr[0].label = _NITF_DEFAULT_TRE_LABEL; + descr[0].tag = NITF_TRE_RAW; + descr[1].data_type = NITF_END; + descr[1].data_count = 0; + descr[1].label = NULL; + descr[1].tag = NULL; + + ((nitf_TREPrivateData*)tre->priv)->description = descr; + + return NITF_SUCCESS; +} + + +NITFPRIV(const char*) defaultGetID(nitf_TRE *tre) +{ + /* always return raw - since it is a raw description */ + return NITF_TRE_RAW; +} + + +NITFPRIV(NITF_BOOL) defaultRead(nitf_IOInterface *io, + nitf_Uint32 length, + nitf_TRE * tre, + struct _nitf_Record* record, + nitf_Error * error) +{ + nitf_Field *field = NULL; + nitf_TREDescription *descr = NULL; + char *data = NULL; + NITF_BOOL success; + + if (!tre) + { + /* set error ??? */ + goto CATCH_ERROR; + } + + /* malloc the space for the raw data */ + data = (char *) NITF_MALLOC(length + 1); + if (!data) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + + goto CATCH_ERROR; + } + memset(data, 0, length + 1); + + descr = + (nitf_TREDescription *) NITF_MALLOC(2 * + sizeof(nitf_TREDescription)); + if (!descr) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + goto CATCH_ERROR; + } + + descr[0].data_type = NITF_BINARY; + descr[0].data_count = length; + descr[0].label = _NITF_DEFAULT_TRE_LABEL; + descr[0].tag = NITF_TRE_RAW; + descr[1].data_type = NITF_END; + descr[1].data_count = 0; + descr[1].label = NULL; + descr[1].tag = NULL; + + tre->priv = nitf_TREPrivateData_construct(error); + if (!tre->priv) + goto CATCH_ERROR; + + ((nitf_TREPrivateData*)tre->priv)->length = length; + ((nitf_TREPrivateData*)tre->priv)->description = descr; + + /* Read the data extension into the tre */ + success = nitf_TREUtils_readField(io, data, (int) length, error); + if (!success) + goto CATCH_ERROR; + + field = nitf_Field_construct(length, NITF_BINARY, error); + if (field == NULL) + { + goto CATCH_ERROR; + } + /* TODO -- likely inefficient, since we end up copying the raw data here */ + if (!nitf_Field_setRawData + (field, (NITF_DATA *) data, length, error)) + { + goto CATCH_ERROR; + } + nitf_HashTable_insert(((nitf_TREPrivateData*)tre->priv)->hash, + NITF_TRE_RAW, field, error); + + NITF_FREE(data); + +#ifdef NITF_PRINT_TRES + printf + ("------------------------------------------------------------\n"); + printf("[%s] length %d (unknown TRE default handler)\n", tre->tag, + length); + printf + ("------------------------------------------------------------\n"); + printf("\n"); +#endif + + return NITF_SUCCESS; + + /* Handle any errors */ +CATCH_ERROR: + if (descr) NITF_FREE(descr); + if (tre && tre->priv) + nitf_TREPrivateData_destruct((nitf_TREPrivateData**)&tre->priv); + return NITF_FAILURE; +} + + +NITFPRIV(NITF_BOOL) defaultWrite(nitf_IOInterface* io, + struct _nitf_TRE* tre, + struct _nitf_Record* record, + nitf_Error* error) +{ + nitf_Field* field; + nitf_Pair* pair = nitf_HashTable_find( + ((nitf_TREPrivateData*)tre->priv)->hash, NITF_TRE_RAW); + if (pair == NULL) + { + nitf_Error_init(error, "No raw_data in default!", NITF_CTXT, NITF_ERR_INVALID_OBJECT); + return NITF_FAILURE; + } + field = (nitf_Field*)pair->data; + + if (!nitf_IOInterface_write(io, field->raw, field->length, error)) + return NITF_FAILURE; + return NITF_SUCCESS; +} + +NITFPRIV(nitf_Pair*) defaultIncrement(nitf_TREEnumerator* it, nitf_Error* error) +{ + if (it && it->data) + { + nitf_Pair* data = nitf_HashTable_find( + ((nitf_TREPrivateData*)it->data)->hash, NITF_TRE_RAW); + if (data) + { + it->data = NULL; /* set to NULL, since we only have one value */ + return data; + } + } + nitf_Error_init(error, "Null iterator!", NITF_CTXT, NITF_ERR_INVALID_OBJECT); + return NULL; +} + +NITFPRIV(NITF_BOOL) defaultHasNext(nitf_TREEnumerator** it) +{ + if (it && *it) + { + if ((*it)->data) + { + /* next hasn't been called yet */ + return NITF_SUCCESS; + } + else + { + /* next was already called once */ + NITF_FREE(*it); + *it = NULL; + return NITF_FAILURE; + } + } + return NITF_FAILURE; +} + + +NITFPRIV(const char*) defaultGetFieldDescription(nitf_TREEnumerator* it, + nitf_Error* error) +{ + if (it && it->data) + { + nitf_TREDescription *desc = &((nitf_TREPrivateData*)it->data)->description[0]; + if (desc->label) + return desc->label; + } + nitf_Error_init(error, "No TRE Description available", + NITF_CTXT, NITF_ERR_INVALID_OBJECT); + return NULL; +} + + +NITFPRIV(nitf_TREEnumerator*) defaultBegin(nitf_TRE* tre, nitf_Error* error) +{ + nitf_TREEnumerator* it = (nitf_TREEnumerator*)NITF_MALLOC(sizeof(nitf_TREEnumerator)); + /* Check rv here */ + it->next = defaultIncrement; + it->hasNext = defaultHasNext; + it->getFieldDescription = defaultGetFieldDescription; + it->data = tre->priv; + + if (!it->data || !nitf_HashTable_find( + ((nitf_TREPrivateData*)it->data)->hash, NITF_TRE_RAW)) + { + nitf_Error_init(error, "No raw_data in default!", NITF_CTXT, NITF_ERR_INVALID_OBJECT); + return NITF_FAILURE; + } + return it; +} + + +NITFPRIV(nitf_List*) defaultFind(nitf_TRE* tre, + const char* pattern, + nitf_Error* error) +{ + nitf_List* list; + + nitf_HashTableIterator it = nitf_HashTable_begin( + ((nitf_TREPrivateData*)tre->priv)->hash); + nitf_HashTableIterator end = nitf_HashTable_end( + ((nitf_TREPrivateData*)tre->priv)->hash); + + list = nitf_List_construct(error); + if (!list) return NULL; + + while (nitf_HashTableIterator_notEqualTo(&it, &end)) + { + nitf_Pair* pair = nitf_HashTableIterator_get(&it); + + if (strstr(pair->key, pattern)) + { + /* Should check this, I suppose */ + nitf_List_pushBack(list, pair, error); + } + nitf_HashTableIterator_increment(&it); + } + + return list; +} + +NITFPRIV(NITF_BOOL) defaultSetField(nitf_TRE * tre, + const char *tag, + NITF_DATA * data, + size_t dataLength, nitf_Error * error) +{ + nitf_Field* field = NULL; + + if (strcmp(tag, NITF_TRE_RAW)) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_INVALID_PARAMETER, "Invalid param [%s]", tag); + return NITF_FAILURE; + } + + field = nitf_Field_construct(dataLength, NITF_BINARY, error); + if (!field) + return NITF_FAILURE; + + /* TODO -- likely inefficient, since we end up copying the raw data here */ + if (!nitf_Field_setRawData(field, (NITF_DATA *) data, dataLength, error)) + return NITF_FAILURE; + + if (nitf_HashTable_exists(((nitf_TREPrivateData*)tre->priv)->hash, tag)) + { + nitf_Field* oldValue; + nitf_Pair* pair = nitf_HashTable_find( + ((nitf_TREPrivateData*)tre->priv)->hash, tag); + oldValue = (nitf_Field*)pair->data; + nitf_Field_destruct(&oldValue); + pair->data = field; + return NITF_SUCCESS; + } + + /* reset the lengths in two places */ + ((nitf_TREPrivateData*)tre->priv)->length = dataLength; + ((nitf_TREPrivateData*)tre->priv)->description[0].data_count = dataLength; + + return nitf_HashTable_insert(((nitf_TREPrivateData*)tre->priv)->hash, + tag, field, error); +} + +NITFPRIV(nitf_Field*) defaultGetField(nitf_TRE* tre, const char* tag) +{ + nitf_Pair* pair = nitf_HashTable_find( + ((nitf_TREPrivateData*)tre->priv)->hash, tag); + if (!pair) return NULL; + return (nitf_Field*)pair->data; +} + + +NITFPRIV(int) defaultGetCurrentSize(nitf_TRE* tre, nitf_Error* error) +{ + /* TODO - should we make sure length is equal to the descr data_count ? */ + return ((nitf_TREPrivateData*)tre->priv)->length; +} + + +NITFPRIV(NITF_BOOL) defaultClone(nitf_TRE *source, + nitf_TRE *tre, + nitf_Error* error) +{ + nitf_TREPrivateData *sourcePriv = NULL; + nitf_TREPrivateData *trePriv = NULL; + + if (!tre || !source || !source->priv) + return NITF_FAILURE; + + sourcePriv = (nitf_TREPrivateData*)source->priv; + + /* this clones the hash */ + if (!(trePriv = nitf_TREPrivateData_clone(sourcePriv, error))) + return NITF_FAILURE; + + /* just copy over the optional length */ + trePriv->length = sourcePriv->length; + + /* setup the description how we want it */ + trePriv->description = (nitf_TREDescription *) NITF_MALLOC( + 2 * sizeof(nitf_TREDescription)); + if (!trePriv->description) + { + nitf_TREPrivateData_destruct(&trePriv); + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + return NITF_FAILURE; + } + + trePriv->description[0].data_type = NITF_BINARY; + trePriv->description[0].data_count = sourcePriv->description[0].data_count; + trePriv->description[0].label = _NITF_DEFAULT_TRE_LABEL; + trePriv->description[0].tag = NITF_TRE_RAW; + trePriv->description[1].data_type = NITF_END; + trePriv->description[1].data_count = 0; + trePriv->description[1].label = NULL; + trePriv->description[1].tag = NULL; + + tre->priv = trePriv; + + return NITF_SUCCESS; +} + + +NITFPRIV(void) defaultDestruct(nitf_TRE *tre) +{ + if (tre && tre->priv) + { + NITF_FREE(((nitf_TREPrivateData*)tre->priv)->description); + nitf_TREPrivateData_destruct((nitf_TREPrivateData**)&tre->priv); + } +} + +NITFAPI(nitf_TREHandler*) nitf_DefaultTRE_handler(nitf_Error * error) +{ + static nitf_TREHandler handler = + { + defaultInit, + defaultGetID, + defaultRead, + defaultSetField, + defaultGetField, + defaultFind, + defaultWrite, + defaultBegin, + defaultGetCurrentSize, + defaultClone, + defaultDestruct, + NULL /* data - We don't need this! */ + }; + + return &handler; +} diff --git a/modules/c/nitf/source/DirectBlockSource.c b/modules/c/nitf/source/DirectBlockSource.c new file mode 100644 index 000000000..8bb03f3ad --- /dev/null +++ b/modules/c/nitf/source/DirectBlockSource.c @@ -0,0 +1,184 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2013, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +/* + * Implementation of the direct block source object + */ + +#include "nitf/DirectBlockSource.h" + +/* The instance data for the rowSource object */ + +typedef struct _DirectBlockSourceImpl +{ + /* Saved constructor arguments */ + void *algorithm; /* The algorithm object */ + /* Pointer to the next row function */ + NITF_DIRECT_BLOCK_SOURCE_NEXT_BLOCK nextBlock; + nitf_ImageReader* imageReader; + nitf_Uint32 blockNumber; + size_t numBlocks; +} +DirectBlockSourceImpl; + +NITFPRIV(DirectBlockSourceImpl *) toDirectBlockSource(NITF_DATA * data, + nitf_Error * error) +{ + DirectBlockSourceImpl *directBlockSource = (DirectBlockSourceImpl *) data; + if (directBlockSource == NULL) + { + nitf_Error_init(error, "Null pointer reference", + NITF_CTXT, NITF_ERR_INVALID_OBJECT); + return NULL; + } + return directBlockSource; +} + + +/* + * DirectBlockSource_read - Read data function for row source + */ + +/* Instance data */ +/* Output buffer */ +NITFPRIV(NITF_BOOL) DirectBlockSource_read(NITF_DATA * data, char *buf, nitf_Off size, /* Amount to read */ + nitf_Error * error) /* For error returns */ +{ + DirectBlockSourceImpl *directBlockSource = toDirectBlockSource(data, error); + nitf_Uint8* block; + nitf_Uint64 blockSize; + + if (!directBlockSource) + return NITF_FAILURE; + + block = nitf_ImageIO_readBlockDirect(directBlockSource->imageReader->imageDeblocker, + directBlockSource->imageReader->input, + directBlockSource->blockNumber++, + &blockSize, error); + if(!block) + return NITF_FAILURE; + + if(!directBlockSource->nextBlock(directBlockSource->algorithm, + buf, + block, + directBlockSource->blockNumber-1, + blockSize, + error)) + { + return NITF_FAILURE; + } + return NITF_SUCCESS; +} + + +/* + * DirectBlockSource_destruct - Destructor for instance data + */ + +/* Instance data to destroy */ +NITFPRIV(void) DirectBlockSource_destruct(NITF_DATA * data) +{ + DirectBlockSourceImpl *impl = (DirectBlockSourceImpl *) data; + if (impl) + { + NITF_FREE(impl); + } +} + +NITFPRIV(nitf_Off) DirectBlockSource_getSize(NITF_DATA * data, nitf_Error *e) +{ + DirectBlockSourceImpl *directBlockSource = (DirectBlockSourceImpl *) data; + return directBlockSource ? directBlockSource->numBlocks : 0; +} + +NITFPRIV(NITF_BOOL) DirectBlockSource_setSize(NITF_DATA * data, nitf_Off numBlocks, nitf_Error *e) +{ + DirectBlockSourceImpl *directBlockSource = (DirectBlockSourceImpl *) data; + if (!directBlockSource) + { + nitf_Error_init(e, "Null pointer reference", + NITF_CTXT, NITF_ERR_INVALID_OBJECT); + return NITF_FAILURE; + } + directBlockSource->numBlocks = numBlocks; + return NITF_SUCCESS; +} + +NITFAPI(nitf_BandSource *) nitf_DirectBlockSource_construct(void * algorithm, + NITF_DIRECT_BLOCK_SOURCE_NEXT_BLOCK + nextBlock, + nitf_ImageReader* imageReader, + nitf_Uint32 numBands, + nitf_Error * error) +{ + static nitf_IDataSource iDirectBlockSource = + { + &DirectBlockSource_read, + &DirectBlockSource_destruct, + &DirectBlockSource_getSize, + &DirectBlockSource_setSize + }; + DirectBlockSourceImpl *impl; + nitf_BandSource *bandSource; + nitf_BlockingInfo* blockInfo; + size_t numBlocks; + + impl = (DirectBlockSourceImpl *) NITF_MALLOC(sizeof(DirectBlockSourceImpl)); + if (!impl) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), NITF_CTXT, + NITF_ERR_MEMORY); + return NULL; + } + + if(!nitf_ImageIO_setupDirectBlockRead(imageReader->imageDeblocker, + imageReader->input, + numBands, + error)) + return NITF_FAILURE; + + blockInfo = nitf_ImageReader_getBlockingInfo(imageReader, error); + if (blockInfo == NULL) + return NITF_FAILURE; + + numBlocks = blockInfo->numBlocksPerRow * blockInfo->numBlocksPerCol; + + nitf_BlockingInfo_destruct(&blockInfo); + + impl->algorithm = algorithm; + impl->nextBlock = nextBlock; + impl->imageReader = imageReader; + impl->blockNumber = 0; + impl->numBlocks = numBlocks; + + bandSource = (nitf_BandSource *) NITF_MALLOC(sizeof(nitf_BandSource)); + if (!bandSource) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), NITF_CTXT, + NITF_ERR_MEMORY); + return NULL; + } + bandSource->data = impl; + bandSource->iface = &iDirectBlockSource; + return bandSource; +} + diff --git a/modules/c/nitf/source/DownSampler.c b/modules/c/nitf/source/DownSampler.c new file mode 100644 index 000000000..a18f978cf --- /dev/null +++ b/modules/c/nitf/source/DownSampler.c @@ -0,0 +1,1062 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/DownSampler.h" + +NITFAPI(void) nitf_DownSampler_destruct(nitf_DownSampler ** downsampler) +{ + if (*downsampler) + { + if ((*downsampler)->data != NULL) + (*downsampler)->iface->destruct((*downsampler)->data); + NITF_FREE(*downsampler); + *downsampler = NULL; + } + +} + +NITFPRIV(NITF_BOOL) PixelSkip_apply(nitf_DownSampler * object, + NITF_DATA ** inputWindows, + NITF_DATA ** outputWindows, + nitf_Uint32 numBands, + nitf_Uint32 numWindowRows, + nitf_Uint32 numWindowCols, + nitf_Uint32 numInputCols, + nitf_Uint32 numCols, + nitf_Uint32 pixelType, + nitf_Uint32 pixelSize, + nitf_Uint32 rowsInLastWindow, + nitf_Uint32 colsInLastWindow, + nitf_Error * error) +{ + nitf_Uint32 row; /* Current row */ + nitf_Uint32 column; /* Current column */ + nitf_Uint32 colInc; /* Column increment */ + nitf_Uint32 rowInc; /* Pointer increment for end of row */ + nitf_Uint32 outRowInc; /* Output pointer increment for end of row */ + nitf_Uint32 band; /* Current band */ + + /* + * Note: The output buffer is at down-sampled resolution and the + * part being created may not span the entire user window. + * Therefore a separate row increment must be calculated. + * + * Since the data is being copied, not interpreted. any type of the right + * size will work. + */ + + colInc = object->colSkip; + rowInc = numInputCols * (object->colSkip - 1); + outRowInc = numCols - numWindowCols; + + switch (pixelSize) + { + case 1: + { + nitf_Uint8 *inp; /* Pointer into input */ + nitf_Uint8 *outp; /* Pointer into output */ + + for (band = 0; band < numBands; band++) + { + inp = (nitf_Uint8 *) inputWindows[band]; + outp = (nitf_Uint8 *) outputWindows[band]; + + for (row = 0; row < numWindowRows; row++) + { + for (column = 0; column < numWindowCols; column++) + { + *(outp++) = *inp; + inp += colInc; + } + inp += rowInc; + outp += outRowInc; + } + } + } + break; + case 2: + { + nitf_Uint16 *inp; /* Pointer into input */ + nitf_Uint16 *outp; /* Pointer into output */ + + for (band = 0; band < numBands; band++) + { + inp = (nitf_Uint16 *) inputWindows[band]; + outp = (nitf_Uint16 *) outputWindows[band]; + + for (row = 0; row < numWindowRows; row++) + { + for (column = 0; column < numWindowCols; column++) + { + *(outp++) = *inp; + inp += colInc; + } + inp += rowInc; + outp += outRowInc; + } + } + } + break; + case 4: + { + nitf_Uint32 *inp; /* Pointer into input */ + nitf_Uint32 *outp; /* Pointer into output */ + + for (band = 0; band < numBands; band++) + { + inp = (nitf_Uint32 *) inputWindows[band]; + outp = (nitf_Uint32 *) outputWindows[band]; + for (row = 0; row < numWindowRows; row++) + { + for (column = 0; column < numWindowCols; column++) + { + *(outp++) = *inp; + inp += colInc; + } + inp += rowInc; + outp += outRowInc; + } + } + } + break; + case 8: + { + nitf_Uint64 *inp; /* Pointer into input */ + nitf_Uint64 *outp; /* Pointer into output */ + + for (band = 0; band < numBands; band++) + { + inp = (nitf_Uint64 *) inputWindows[band]; + outp = (nitf_Uint64 *) outputWindows[band]; + + for (row = 0; row < numWindowRows; row++) + { + for (column = 0; column < numWindowCols; column++) + { + *(outp++) = *inp; + inp += colInc; + } + inp += rowInc; + outp += outRowInc; + } + } + } + break; + case 16: /* It's not clear if this case is actually possible */ + { + nitf_Uint64 *inp; /* Pointer into input */ + nitf_Uint64 *outp; /* Pointer into output */ + + colInc *= 2; + rowInc *= 2; + outRowInc *= 2; + + for (band = 0; band < numBands; band++) + { + inp = (nitf_Uint64 *) inputWindows[band]; + outp = (nitf_Uint64 *) outputWindows[band]; + + for (row = 0; row < numWindowRows; row++) + { + for (column = 0; column < numWindowCols; column++) + { + *(outp++) = *inp; + *(outp++) = *inp; + inp += colInc; + } + inp += rowInc; + outp += outRowInc; + } + } + } + break; + + } + + return NITF_SUCCESS; +} + + + +NITFPRIV(void) PixelSkip_destruct(NITF_DATA * data) +{ + return; /* There is no implementation data */ +} + +NITFAPI(nitf_DownSampler *) nitf_PixelSkip_construct(nitf_Uint32 rowSkip, + nitf_Uint32 colSkip, + nitf_Error * error) +{ + + static nitf_IDownSampler iPixelSkip = + { + &PixelSkip_apply, + &PixelSkip_destruct + }; + + nitf_DownSampler *downsampler; + + downsampler = + (nitf_DownSampler *) NITF_MALLOC(sizeof(nitf_DownSampler)); + if (!downsampler) + { + nitf_Error_init(error, + NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + return NULL; + } + + downsampler->rowSkip = rowSkip; + downsampler->colSkip = colSkip; + downsampler->multiBand = 0; + downsampler->minBands = 1; + downsampler->maxBands = 0; + downsampler->types = NITF_DOWNSAMPLER_TYPE_ALL; + downsampler->data = NULL; + + downsampler->iface = &iPixelSkip; + return downsampler; +} + +/* Max down-sample method */ + +/* In the following, the row and column indexes are the row in the array of +* windows, the winRow and winColumn are the row and column within the current +* sample window +* +* The complex case calculates the max of the absolute value +*/ + +#define MAX_DOWN_SAMPLE(type) \ + { \ + nitf_Uint32 colSkip; /* Column skip */ \ + nitf_Uint32 rowSkip; /* Row skip */ \ + nitf_Uint32 colInc; /* Column increment */ \ + nitf_Uint32 rowInc; /* Pointer increment for end of row */ \ + nitf_Uint32 outRowInc; /* Output pointer increment for end of row */ \ + nitf_Uint32 winRowInc; /* Row increment, current window */ \ + nitf_Uint32 row; /* Current row */ \ + nitf_Uint32 column; /* Current column */ \ + nitf_Uint32 winRow; /* Current row in current window */ \ + nitf_Uint32 winCol; /* Current column current window */ \ + nitf_Uint32 rowWinLimit; /* Number of rows in current window */ \ + type *currentRowPtr; /* Pointer to the current window row */ \ + type *currentPtr; /* Pointer to the current window UL corner */ \ + type *pixel; /* Pointer to the current pixel */ \ + type maxValue; /* Current maximum value */ \ + type *outp; /* Pointer into output */ \ + \ + colSkip = object->colSkip; \ + rowSkip = object->rowSkip; \ + colInc = colSkip; \ + rowInc = numInputCols*colSkip*rowSkip; \ + winRowInc = numInputCols-colSkip; \ + outRowInc = numCols - numWindowCols; \ + \ + for(band=0;bandcolSkip; \ + rowSkip = object->rowSkip; \ + colInc = colSkip*2; \ + rowInc = (numWindowCols*colSkip*rowSkip)*2; \ + winRowInc = (numCols - colSkip)*2; \ + outRowInc = (numCols - numWindowCols)*2; \ + \ + for(band=0;bandrowSkip = rowSkip; + downsampler->colSkip = colSkip; + downsampler->multiBand = 0; + downsampler->minBands = 1; + downsampler->maxBands = 0; + downsampler->types = NITF_DOWNSAMPLER_TYPE_ALL; + downsampler->data = NULL; + + downsampler->iface = &iMaxDownSample; + return downsampler; +} + +/* +* Sum of square, two band, down-sample method +* +* The maximum is calculated as the sum of the sum of squares of two bands. +* The caller must supply exactly two bands. The complex pixel type as the +* individual band pixel type is not supported +*/ + +/* In the following, the row and column indexes are the row in the array of +* windows, the winRow and winColumn are the row and column within the current +* sample window +* +*/ + +#define SUM_SQ_2_DOWN_SAMPLE(type) \ + { \ + nitf_Uint32 colSkip; /* Column skip */ \ + nitf_Uint32 rowSkip; /* Row skip */ \ + nitf_Uint32 colInc; /* Column increment */ \ + nitf_Uint32 rowInc; /* Pointer increment for end of row */ \ + nitf_Uint32 outRowInc; /* Output pointer increment for end of row */ \ + nitf_Uint32 winRowInc; /* Row increment, current window */ \ + nitf_Uint32 row; /* Current row */ \ + nitf_Uint32 column; /* Current column */ \ + nitf_Uint32 winRow; /* Current row in current window */ \ + nitf_Uint32 winCol; /* Current column current window */ \ + nitf_Uint32 rowWinLimit; /* Number of rows in current window */ \ + type *outp0; /* Pointer into output, band 0 */ \ + type *outp1; /* Pointer into output, band 0 */ \ + type *currentRowPtr0; /* Pointer to the current window row, band 0 */ \ + type *currentRowPtr1; /* Pointer to the current window row, band 1 */ \ + type *currentPtr0; /* Pointer to the current window UL \ + corner, band 0 */ \ + type *currentPtr1; /* Pointer to the current window UL \ + corner, band 1 */ \ + type *pixel0; /* Pointer to the current pixel, band 0 */ \ + type *pixel1; /* Pointer to the current pixel, band 1 */ \ + float maxValue; /* Current maximum test value */ \ + float maxTest; /* Test maximum value */ \ + type value0; /* Max value pixel band 0 value */ \ + type value1; /* Max value pixel band 1 value */ \ + \ + colSkip = object->colSkip; \ + rowSkip = object->rowSkip; \ + colInc = colSkip; \ + rowInc = numInputCols*colSkip*rowSkip; \ + winRowInc = numInputCols-colSkip; \ + outRowInc = numCols - numWindowCols; \ + \ + currentRowPtr0 = (type *) inputWindows[0]; \ + currentRowPtr1 = (type *) inputWindows[1]; \ + outp0 = (type *) outputWindows[0]; \ + outp1 = (type *) outputWindows[1]; \ + for(row=0;rowrowSkip = rowSkip; + downsampler->colSkip = colSkip; + downsampler->multiBand = 1; + downsampler->minBands = 2; + downsampler->maxBands = 2; + downsampler->types = NITF_DOWNSAMPLER_TYPE_ALL_BUT_COMPLEX; + downsampler->data = NULL; + + downsampler->iface = &iSumSq2DownSample; + return downsampler; +} + + +/* +* First band select, two band, down-sample method +* +* The maximum is calculated as the value of the first band. The caller must +* supply exactly two bands. The complex pixel type as the +* individual band pixel type is not supported +*/ + +/* In the following, the row and column indexes are the row in the array of +* windows, the winRow and winColumn are the row and column within the current +* sample window +* +*/ + +#define SELECT_2_DOWN_SAMPLE(type) \ + { \ + nitf_Uint32 colSkip; /* Column skip */ \ + nitf_Uint32 rowSkip; /* Row skip */ \ + nitf_Uint32 colInc; /* Column increment */ \ + nitf_Uint32 rowInc; /* Pointer increment for end of row */ \ + nitf_Uint32 outRowInc; /* Output pointer increment for end of row */ \ + nitf_Uint32 winRowInc; /* Row increment, current window */ \ + nitf_Uint32 row; /* Current row */ \ + nitf_Uint32 column; /* Current column */ \ + nitf_Uint32 winRow; /* Current row in current window */ \ + nitf_Uint32 winCol; /* Current column current window */ \ + nitf_Uint32 rowWinLimit; /* Number of rows in current window */ \ + type *outp0; /* Pointer into output, band 0 */ \ + type *outp1; /* Pointer into output, band 0 */ \ + type *currentRowPtr0; /* Pointer to the current window row, band 0 */ \ + type *currentRowPtr1; /* Pointer to the current window row, band 1 */ \ + type *currentPtr0; /* Pointer to the current window UL \ + corner, band 0 */ \ + type *currentPtr1; /* Pointer to the current window UL \ + corner, band 1 */ \ + type *pixel0; /* Pointer to the current pixel, band 0 */ \ + type *pixel1; /* Pointer to the current pixel, band 1 */ \ + float maxValue; /* Current maximum test value */ \ + type value0; /* Max value pixel band 0 value */ \ + type value1; /* Max value pixel band 1 value */ \ + \ + colSkip = object->colSkip; \ + rowSkip = object->rowSkip; \ + colInc = colSkip; \ + rowInc = numInputCols*colSkip*rowSkip; \ + winRowInc = numInputCols-colSkip; \ + outRowInc = numCols - numWindowCols; \ + \ + currentRowPtr0 = (type *) inputWindows[0]; \ + currentRowPtr1 = (type *) inputWindows[1]; \ + outp0 = (type *) outputWindows[0]; \ + outp1 = (type *) outputWindows[1]; \ + for(row=0;rowrowSkip = rowSkip; + downsampler->colSkip = colSkip; + downsampler->multiBand = 1; + downsampler->minBands = 2; + downsampler->maxBands = 2; + downsampler->types = NITF_DOWNSAMPLER_TYPE_ALL_BUT_COMPLEX; + downsampler->data = NULL; + + downsampler->iface = &iSelect2DownSample; + return downsampler; +} diff --git a/modules/c/nitf/source/Extensions.c b/modules/c/nitf/source/Extensions.c new file mode 100644 index 000000000..7222d5ae8 --- /dev/null +++ b/modules/c/nitf/source/Extensions.c @@ -0,0 +1,474 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/Extensions.h" + + +NITFPRIV(int) eraseIt(nitf_HashTable * ht, + nitf_Pair * pair, NITF_DATA* userData, nitf_Error * error); + +NITFPRIV(NITF_BOOL) insertToHash( nitf_HashTable* hash, const char* name, + nitf_TRE* tre, nitf_Error* error); + +NITFAPI(nitf_Extensions *) nitf_Extensions_construct(nitf_Error * error) +{ + /* Allocate the extensions section */ + nitf_Extensions *ext = + (nitf_Extensions *) NITF_MALLOC(sizeof(nitf_Extensions)); + if (!ext) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + return NULL; + } + /* Make sure we NULL-set this so we dont have any problems */ + ext->ref = NULL; + + /* Construct the hash -- it WILL, autodelete its chains */ + /* And we will autodelete our list items */ + ext->hash = nitf_HashTable_construct(NITF_TRE_HASH_SIZE, error); + if (!ext->hash) + { + /* If there is failure, cleanup */ + nitf_Extensions_destruct(&ext); + return NULL; + } + ext->ref = nitf_List_construct(error); + if (!ext->ref) + { + nitf_Extensions_destruct(&ext); + return NULL; + } + + nitf_HashTable_setPolicy(ext->hash, NITF_DATA_RETAIN_OWNER); + return ext; +} + + +NITFAPI(nitf_Extensions *) nitf_Extensions_clone(nitf_Extensions * source, + nitf_Error * error) +{ + + /* In this case, using the constructor is easiest here */ + nitf_Extensions *ext = NULL; + if (source) + { + nitf_ListIterator currentRef; + nitf_ListIterator treRefEnd; + + ext = (nitf_Extensions *) NITF_MALLOC(sizeof(nitf_Extensions)); + if (!ext) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + return NULL; + } + + /* Make sure to set this to NULL to avoid any problems */ + ext->ref = NULL; + + /* Create the hash */ + ext->hash = + nitf_HashTable_construct(source->hash->nbuckets, error); + if (!ext->hash) + { + nitf_Extensions_destruct(&ext); + return NULL; + } + + + /* + * First, clone the list of TREs. This is the easiest thing + * to do anyway + * + */ + if ( (ext->ref = nitf_List_clone(source->ref, + (NITF_DATA_ITEM_CLONE) + nitf_TRE_clone, + error)) == NULL ) + { + nitf_Extensions_destruct(&ext); + return NULL; + } + + currentRef = nitf_List_begin(ext->ref); + treRefEnd = nitf_List_end(ext->ref); + + /* Go through and insert each thing */ + while ( nitf_ListIterator_notEqualTo( ¤tRef, + &treRefEnd ) ) + { + + nitf_TRE* tre = (nitf_TRE*) nitf_ListIterator_get(¤tRef);/*(ext->ref);*/ + if (!insertToHash( ext->hash, tre->tag, tre, error )) + { + nitf_Extensions_destruct(&ext); + return NULL; + } + nitf_ListIterator_increment(¤tRef); + } + } + else + { + nitf_Error_initf(error, + NITF_CTXT, + NITF_ERR_INVALID_OBJECT, + "Trying to clone NULL pointer"); + } + return ext; +} + + +NITFAPI(void) nitf_Extensions_destruct(nitf_Extensions ** ext) +{ + + /* If we have a handle still */ + if ((*ext)) + { + + /* If it owns a valid hash */ + if ((*ext)->hash) + { + + /* We want to delete the chain */ + nitf_Error e; + NITF_HASH_FUNCTOR deleteHashChain = eraseIt; + + /* Each hash value is a linked list */ + /* Even though we told the hash to kill our list */ + /* It doesnt know how to kill our list node values */ + /* So we kill each one of them in this iterative function */ + /* And we let the hash table think its doing the real work */ + nitf_HashTable_foreach((*ext)->hash, deleteHashChain, NULL, &e); + + /* Now we kill the hash table */ + nitf_HashTable_destruct(&((*ext)->hash)); + + } + /* These are all just dead references, so we just want + to get rid of the list, not delete anything */ + if ((*ext)->ref) + { + nitf_List *l = (*ext)->ref; + while (!nitf_List_isEmpty(l)) + { + (void) nitf_List_popFront(l); + } + nitf_List_destruct(&l); + } + NITF_FREE(*ext); + + /* Null-set this so it doesnt happen again */ + *ext = NULL; + } + +} + +NITFAPI(NITF_BOOL) nitf_Extensions_appendTRE(nitf_Extensions * ext, + nitf_TRE * tre, + nitf_Error * error) +{ + + if (!insertToHash(ext->hash, tre->tag, tre, error)) + return NITF_FAILURE; + + /* Okay this is pretty unlikely */ + if (!nitf_List_pushBack(ext->ref, tre, error)) + { + /* Im not addressing the potentially inconsistent state + here. The net effect is that if you can't push it on + here, but you somehow got it in the hash, you can modify + that till the cows come home, but it won't show up on a write */ + return NITF_FAILURE; + } + + return NITF_SUCCESS; +} + + +NITFAPI(nitf_List *) nitf_Extensions_getTREsByName(nitf_Extensions * ext, + const char *name) +{ + nitf_Pair *pair = nitf_HashTable_find(ext->hash, name); + if (!pair) + return NULL; + else + { + return (nitf_List *) pair->data; + } +} + + +NITFAPI(NITF_BOOL) nitf_Extensions_exists(nitf_Extensions * ext, + const char *name) +{ + return nitf_HashTable_exists(ext->hash, name); +} + + + +NITFAPI(void) nitf_Extensions_removeTREsByName(nitf_Extensions * ext, + const char *name) +{ + /* Do LL first, its easy */ + nitf_Pair* pair; + nitf_Error error; + nitf_ListIterator iter = nitf_List_begin(ext->ref); + nitf_ListIterator end = nitf_List_end(ext->ref); + while (nitf_ListIterator_notEqualTo(&iter, &end)) + { + /* We remove this but don't delete it */ + nitf_TRE* tre = (nitf_TRE*)nitf_ListIterator_get(&iter); + /* If this reference is to a TRE of this name */ + if ( strcmp(tre->tag, name) == 0 ) + { + /* Remove it, which advances the iterator */ + nitf_List_remove(ext->ref, &iter); + } + else + { + /* Advance the iterator */ + nitf_ListIterator_increment(&iter); + } + } + /* Find the list that matches and obliterate it */ + pair = nitf_HashTable_find(ext->hash, name); + + (void) eraseIt(ext->hash, pair, NULL, &error); + nitf_HashTable_remove(ext->hash, name); +} + + +NITFAPI(nitf_ExtensionsIterator) nitf_Extensions_begin(nitf_Extensions * + ext) +{ + /* The iterator to return */ + nitf_ExtensionsIterator extIt; + + /* Be ruthless with our assertions */ + assert(ext); + + extIt.iter = nitf_List_begin(ext->ref); + return extIt; +} + + +NITFAPI(nitf_ExtensionsIterator) nitf_Extensions_end(nitf_Extensions * ext) +{ + nitf_ExtensionsIterator extIt; + + /* Be ruthless with our assertions */ + assert(ext); + extIt.iter = nitf_List_end(ext->ref); + return extIt; +} + + +NITFAPI(void) nitf_ExtensionsIterator_increment(nitf_ExtensionsIterator * + extIt) +{ + nitf_ListIterator_increment(&extIt->iter); +} + + +NITFAPI(nitf_TRE *) nitf_ExtensionsIterator_get(nitf_ExtensionsIterator * + extIt) +{ + return (nitf_TRE *) nitf_ListIterator_get(&extIt->iter); +} + +NITFAPI(NITF_BOOL) nitf_Extensions_insert(nitf_Extensions* ext, + nitf_ExtensionsIterator* extIt, + nitf_TRE* tre, + nitf_Error* error) +{ + /* The easy part, put in list */ + if (!nitf_List_insert(ext->ref, extIt->iter, tre, error)) + return NITF_FAILURE; + /* Now insert to hash */ + return insertToHash( ext->hash, tre->tag, tre, error); +} + +NITFAPI(nitf_TRE *) nitf_Extensions_remove(nitf_Extensions* ext, + nitf_ExtensionsIterator* extIt, + nitf_Error* error) +{ + /* The easy part, remove from list */ + nitf_TRE* tre = (nitf_TRE*)nitf_List_remove(ext->ref, &(extIt->iter)); + nitf_List* treInstances; + nitf_ListIterator it; + nitf_ListIterator end; + + if ( tre == NULL ) + { + nitf_Error_init(error, "Undefined TRE at iterator position", + NITF_CTXT, NITF_ERR_INVALID_OBJECT); + return NULL; + } + /* Trick here is to remove the correct TRE from the hash */ + + /* Start by getting them all... */ + treInstances = nitf_Extensions_getTREsByName(ext, tre->tag); + + /* If this happens we have a big problem: */ + /* Somehow the reference list is different from the hash */ + assert( ! nitf_List_isEmpty(treInstances) ); + + + it = nitf_List_begin( treInstances ); + end = nitf_List_end( treInstances ); + + /* Compare TRE pointers, and drop the right one */ + while ( nitf_ListIterator_notEqualTo(&it, &end) ) + { + + if ( tre == (nitf_TRE*)nitf_ListIterator_get(&it) ) + { + nitf_List_remove(treInstances, &it); + break; + } + nitf_ListIterator_increment(&it); + } + + /* Then if the list is empty, blow away the hash entry */ + if (nitf_List_isEmpty(treInstances)) + { + nitf_List_destruct(&treInstances); + nitf_HashTable_remove(ext->hash, tre->tag); + } + + return tre; +} + +NITFAPI(NITF_BOOL) nitf_ExtensionsIterator_equals(nitf_ExtensionsIterator * + it1, + nitf_ExtensionsIterator * + it2) +{ + return nitf_ListIterator_equals(&it1->iter, &it2->iter); +} + + +NITFAPI(NITF_BOOL) +nitf_ExtensionsIterator_notEqualTo(nitf_ExtensionsIterator * it1, + nitf_ExtensionsIterator * it2) +{ + return nitf_ListIterator_notEqualTo(&it1->iter, &it2->iter); +} + + +NITFAPI(nitf_Uint32) nitf_Extensions_computeLength +(nitf_Extensions * ext, nitf_Version fver, nitf_Error * error) +{ + nitf_Uint32 dataLength = 0; + nitf_ExtensionsIterator iter, end; + nitf_TRE *tre; + + if (ext != NULL) + { + /* set up iterators */ + iter = nitf_Extensions_begin(ext); + end = nitf_Extensions_end(ext); + + /* First, figure out if we have to write any TREs */ + while (nitf_ExtensionsIterator_notEqualTo(&iter, &end)) + { + tre = (nitf_TRE *) nitf_ExtensionsIterator_get(&iter); + + /* if unknown length, we need to compute it */ + dataLength += (nitf_Uint32)tre->handler->getCurrentSize(tre, error); + dataLength += NITF_ETAG_SZ + NITF_EL_SZ; + + /* increment */ + nitf_ExtensionsIterator_increment(&iter); + } + } + return dataLength; +} + +NITFPRIV(NITF_BOOL) insertToHash( nitf_HashTable* hash, const char* name, + nitf_TRE* tre, nitf_Error* error) +{ + + int createdTREList = 0; + nitf_List* tres = NULL; + nitf_Pair* pair = nitf_HashTable_find(hash, name); + /* First thing's first, do we have a list or don't we? */ + + if (pair) + { + tres = (nitf_List*)pair->data; + } + else + { + createdTREList = 1; + tres = nitf_List_construct(error); + if (! tres ) + { + return NITF_FAILURE; + } + if (!nitf_HashTable_insert(hash, name, (NITF_DATA *) tres, error)) + { + + nitf_List_destruct(&tres); + return NITF_FAILURE; + } + } + + /* Now that we know we have a list, make sure we insert into it */ + if ( !nitf_List_pushBack( tres, tre, error ) ) + { + if ( createdTREList ) + { + nitf_List_destruct(&tres); + nitf_HashTable_remove(hash, name ); + } + return NITF_FAILURE; + } + + return NITF_SUCCESS; + +} + +NITFPRIV(int) eraseIt(nitf_HashTable * ht, + nitf_Pair * pair, NITF_DATA* userData, nitf_Error * error) +{ + if (!pair) + return 0; + else + { + + nitf_List *list = (nitf_List *) pair->data; + nitf_ListIterator iter = nitf_List_begin(list); + nitf_ListIterator end = nitf_List_end(list); + while (nitf_ListIterator_notEqualTo(&iter, &end)) + { + + /* This auto-increments for us */ + nitf_TRE *tre = (nitf_TRE *) nitf_List_remove(list, &iter); + nitf_TRE_destruct(&tre); + } + + nitf_List_destruct((nitf_List **) & (pair->data)); + return 1; + } +} diff --git a/modules/c/nitf/source/Field.c b/modules/c/nitf/source/Field.c new file mode 100644 index 000000000..bba14b90c --- /dev/null +++ b/modules/c/nitf/source/Field.c @@ -0,0 +1,1213 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/Field.h" + +/* Spaces are added to the right */ +NITF_BOOL copyAndFillSpaces(nitf_Field * field, + const char *data, + size_t dataLength, nitf_Error * error) +{ + memcpy(field->raw, data, dataLength); + memset(field->raw + dataLength, ' ', field->length - dataLength); + return NITF_SUCCESS; +} + +/* Zeros are added to the left */ +NITF_BOOL copyAndFillZeros(nitf_Field * field, + const char *data, + size_t dataLength, nitf_Error * error) +{ + size_t zeros = field->length - dataLength; + memset(field->raw, '0', zeros); + memcpy(field->raw + zeros, data, dataLength); + + /* Check for sign */ + + /* Sign */ + if ((zeros != 0) && ((data[0] == '+') || (data[0] == '-'))) + { + field->raw[0] = data[0]; + (field->raw + zeros)[0] = '0'; + } + return NITF_SUCCESS; +} + +NITFAPI(nitf_Field *) nitf_Field_construct(size_t length, + nitf_FieldType type, + nitf_Error * error) +{ + nitf_Field *field = NULL; + + if (length == 0) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_INVALID_PARAMETER, + "Cannot create field of size 0"); + goto CATCH_ERROR; + } + + field = (nitf_Field *) NITF_MALLOC(sizeof(nitf_Field)); + if (!field) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + goto CATCH_ERROR; + } + + field->type = type; + field->raw = NULL; + field->length = 0; /* this gets set by resizeField */ + field->resizable = 1; /* set to 1 so we can use the resize code */ + + if (!nitf_Field_resizeField(field, length, error)) + goto CATCH_ERROR; + + field->resizable = 0; /* set to 0 - the default value */ + + return field; + + CATCH_ERROR: + if (field) nitf_Field_destruct(&field); + return NULL; +} + + +NITFAPI(NITF_BOOL) nitf_Field_setRawData(nitf_Field * field, + NITF_DATA * data, + size_t dataLength, + nitf_Error * error) +{ + /* check for NULL data */ + if (field == NULL || data == NULL) + { + nitf_Error_init(error, "NULL data", + NITF_CTXT, NITF_ERR_INVALID_PARAMETER); + return NITF_FAILURE; + } + + /* if it's resizable and a different length, we resize */ + if (field->resizable && dataLength != field->length) + { + if (!nitf_Field_resizeField(field, dataLength, error)) + return NITF_FAILURE; + } + + /* Should we also offer adoption? */ + if (dataLength > field->length) + { + nitf_Error_init(error, "Invalid data length", + NITF_CTXT, NITF_ERR_INVALID_PARAMETER); + return NITF_FAILURE; + } + /* If it is the exact length, just memcpy */ + if (field->length == dataLength) + { + memcpy(field->raw, data, field->length); + return NITF_SUCCESS; + } + /* If it is not the exact length, and it is BCS-A, fill right */ + else if (field->type == NITF_BCS_A) + return copyAndFillSpaces(field, (const char *) data, dataLength, + error); + else if (field->type == NITF_BCS_N) + return copyAndFillZeros(field, (const char *) data, dataLength, + error); + + /* Otherwise, we are failures -- it was binary and the length + didnt match! + if (dataLength != field->length && field->type == NITF_BINARY) + */ + + nitf_Error_init(error, "Invalid data length", + NITF_CTXT, NITF_ERR_INVALID_PARAMETER); + return NITF_FAILURE; +} + + +/* Helper for trimming strings */ + +NITFAPI(void) nitf_Field_trimString(char *str) +{ + nitf_Utils_trimString(str); +} + + +/* Set a number field from a uint32 */ + +NITFAPI(NITF_BOOL) nitf_Field_setUint32(nitf_Field * field, + nitf_Uint32 number, + nitf_Error * error) +{ + char numberBuffer[20]; /* Holds converted number */ + nitf_Uint32 numberLen; /* Length of converted number string */ + + /* Check the field type */ + + if (field->type == NITF_BINARY) + { + nitf_Error_init(error, "Integer set for binary field ", + NITF_CTXT, NITF_ERR_INVALID_PARAMETER); + return (NITF_FAILURE); + } + + /* Convert the number to a string */ + + NITF_SNPRINTF(numberBuffer, 20, "%lu", (unsigned long) number); + numberLen = strlen(numberBuffer); + + /* if it's resizable and a different length, we resize */ + if (field->resizable && numberLen != field->length) + { + if (!nitf_Field_resizeField(field, numberLen, error)) + return NITF_FAILURE; + } + + if (numberLen > field->length) + { + nitf_Error_init(error, "Value for field is too long", + NITF_CTXT, NITF_ERR_INVALID_PARAMETER); + return (NITF_FAILURE); + } + + /* Transfer and pad result */ + + if (field->type == NITF_BCS_N) + copyAndFillZeros(field, numberBuffer, numberLen, error); + else + copyAndFillSpaces(field, numberBuffer, numberLen, error); + + return (NITF_SUCCESS); +} + + +/* Set a number field from a uint64 */ + +NITFAPI(NITF_BOOL) nitf_Field_setUint64(nitf_Field * field, + nitf_Uint64 number, + nitf_Error * error) +{ + char numberBuffer[20]; /* Holds converted number */ + nitf_Uint32 numberLen; /* Length of converted number string */ + + /* Check the field type */ + + if (field->type == NITF_BINARY) + { + nitf_Error_init(error, "Integer set for binary field ", + NITF_CTXT, NITF_ERR_INVALID_PARAMETER); + return (NITF_FAILURE); + } + + /* Convert thte number to a string */ + + NITF_SNPRINTF(numberBuffer, 20, "%llu", number); + numberLen = strlen(numberBuffer); + + /* if it's resizable and a different length, we resize */ + if (field->resizable && numberLen != field->length) + { + if (!nitf_Field_resizeField(field, numberLen, error)) + return NITF_FAILURE; + } + + if (numberLen > field->length) + { + nitf_Error_init(error, "Value for BCS_N field is too long", + NITF_CTXT, NITF_ERR_INVALID_PARAMETER); + return (NITF_FAILURE); + } + + /* Transfer and pad result */ + + if (field->type == NITF_BCS_N) + copyAndFillZeros(field, numberBuffer, numberLen, error); + else + copyAndFillSpaces(field, numberBuffer, numberLen, error); + + return (NITF_SUCCESS); +} + +/* Set a number field from a int32 */ + +NITFAPI(NITF_BOOL) nitf_Field_setInt32(nitf_Field * field, + nitf_Int32 number, + nitf_Error * error) +{ + char numberBuffer[20]; /* Holds converted number */ + nitf_Uint32 numberLen; /* Length of converted number string */ + + /* Check the field type */ + + if (field->type == NITF_BINARY) + { + nitf_Error_init(error, "Integer set for binary field ", + NITF_CTXT, NITF_ERR_INVALID_PARAMETER); + return (NITF_FAILURE); + } + + /* Convert the number to a string */ + + NITF_SNPRINTF(numberBuffer, 20, "%ld", (long) number); + numberLen = strlen(numberBuffer); + + /* if it's resizable and a different length, we resize */ + if (field->resizable && numberLen != field->length) + { + if (!nitf_Field_resizeField(field, numberLen, error)) + return NITF_FAILURE; + } + + if (numberLen > field->length) + { + nitf_Error_init(error, "Value for field is too long", + NITF_CTXT, NITF_ERR_INVALID_PARAMETER); + return (NITF_FAILURE); + } + + /* Transfer and pad result */ + + if (field->type == NITF_BCS_N) + copyAndFillZeros(field, numberBuffer, numberLen, error); + else + copyAndFillSpaces(field, numberBuffer, numberLen, error); + + return (NITF_SUCCESS); +} + +/* Set a number field from a int64 */ + +NITFAPI(NITF_BOOL) nitf_Field_setInt64(nitf_Field * field, + nitf_Int64 number, + nitf_Error * error) +{ + char numberBuffer[20]; /* Holds converted number */ + nitf_Uint32 numberLen; /* Length of converted number string */ + + /* Check the field type */ + + if (field->type == NITF_BINARY) + { + nitf_Error_init(error, "Integer set for binary field ", + NITF_CTXT, NITF_ERR_INVALID_PARAMETER); + return (NITF_FAILURE); + } + + /* Convert thte number to a string */ + + NITF_SNPRINTF(numberBuffer, 20, "%lld", number); + numberLen = strlen(numberBuffer); + + /* if it's resizable and a different length, we resize */ + if (field->resizable && numberLen != field->length) + { + if (!nitf_Field_resizeField(field, numberLen, error)) + return NITF_FAILURE; + } + + if (numberLen > field->length) + { + nitf_Error_init(error, "Value for BCS_N field is too long", + NITF_CTXT, NITF_ERR_INVALID_PARAMETER); + return (NITF_FAILURE); + } + + /* Transfer and pad result */ + + if (field->type == NITF_BCS_N) + copyAndFillZeros(field, numberBuffer, numberLen, error); + else + copyAndFillSpaces(field, numberBuffer, numberLen, error); + + return (NITF_SUCCESS); +} + +/* Set a string field */ + +NITFPRIV(NITF_BOOL) isBCSN(const char *str, nitf_Uint32 len, nitf_Error * error); +NITFPRIV(NITF_BOOL) isBCSA(const char *str, nitf_Uint32 len, nitf_Error * error); + +NITFAPI(NITF_BOOL) nitf_Field_setString(nitf_Field * field, + const char *str, nitf_Error * error) +{ + nitf_Uint32 strLen; /* Length of input string */ + + /* Check the field type */ + + if (field->type == NITF_BINARY) + { + nitf_Error_init(error, + "Type for string set for field can not be binary", + NITF_CTXT, NITF_ERR_INVALID_PARAMETER); + return (NITF_FAILURE); + } + + /* Transfer and pad result (check for correct characters) */ + + strLen = strlen(str); + + /* if it's resizable and a different length, we resize */ + if (field->resizable && strLen != field->length) + { + if (!nitf_Field_resizeField(field, strLen, error)) + return NITF_FAILURE; + } + + if (strLen > field->length) + { + nitf_Error_init(error, "Value for field is too long", + NITF_CTXT, NITF_ERR_INVALID_PARAMETER); + return (NITF_FAILURE); + } + + if (field->type == NITF_BCS_A) + { + if (!isBCSA(str, strLen, error)) + return (NITF_FAILURE); + copyAndFillSpaces(field, str, strLen, error); + } + else + { + if (!isBCSN(str, strLen, error)) + return (NITF_FAILURE); + copyAndFillZeros(field, str, strLen, error); + } + + return (NITF_SUCCESS); +} + +NITFAPI(NITF_BOOL) nitf_Field_setDateTime(nitf_Field * field, + const nitf_DateTime *dateTime, const char *dateFormat, nitf_Error * error) +{ + double millis; + + /* Check the field type */ + if (field->type == NITF_BINARY) + { + nitf_Error_init(error, + "Type for date set for field can not be binary", + NITF_CTXT, NITF_ERR_INVALID_PARAMETER); + return (NITF_FAILURE); + } + + millis = dateTime ? dateTime->timeInMillis : + nitf_Utils_getCurrentTimeMillis(); + + return nitf_DateTime_formatMillis(millis, dateFormat, + field->raw, field->length + 1, error); +} + + +NITFAPI(nitf_DateTime*) nitf_Field_asDateTime(nitf_Field * field, + const char* dateFormat, nitf_Error * error) +{ + nitf_DateTime *dateTime = NULL; + /* Check the field type */ + if (field->type == NITF_BINARY) + { + nitf_Error_init(error, + "Type for date field can not be binary", + NITF_CTXT, NITF_ERR_INVALID_PARAMETER); + return NULL; + } + + return nitf_DateTime_fromString(field->raw, dateFormat, error); +} + +/* Set a real field */ + +NITFAPI(NITF_BOOL) nitf_Field_setReal(nitf_Field * field, + const char *type, NITF_BOOL plus, + double value, nitf_Error *error) +{ + nitf_Uint32 precision; /* Format precision */ + nitf_Uint32 bufferLen; /* Length of buffer */ + char *buffer; /* Holds intermediate and final results */ + char fmt[64]; /* Format used */ + + /* Check type */ + + if ( + (strcmp(type, "f") != 0) + && (strcmp(type, "e") != 0) + && (strcmp(type, "E") != 0)) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_INVALID_PARAMETER, + "Invalid conversion type %s", type); + return(NITF_FAILURE); + } + + /* Allocate buffer used to build value */ + + /* The 64 covers the puncuation and exponent and is overkill */ + bufferLen = field->length * 2 + 64; + buffer = (char* )NITF_MALLOC(bufferLen + 1); + if (buffer == NULL) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + return(NITF_FAILURE); + } + + /* + Try a precision that will be too large and then adjust it based on the + length of what you get. This results in a left justified string with the + maximum number of decmal places. What you are actually figuring is the + number of digits in the whole part of the number. + */ + + precision = field->length; /* Must be too big */ + if (plus) + NITF_SNPRINTF(fmt, 64, "%%+-1.%dl%s", precision, type); + else + NITF_SNPRINTF(fmt, 64, "%%-1.%dl%s", precision, type); + NITF_SNPRINTF(buffer, bufferLen + 1, fmt, value); + + bufferLen = strlen(buffer); + + /* if it's resizable and a different length, we resize */ + if (field->resizable && bufferLen != field->length) + { + if (!nitf_Field_resizeField(field, bufferLen, error)) + return NITF_FAILURE; + } + + if (bufferLen > field->length) + { + if (precision > bufferLen - field->length) + precision -= bufferLen - field->length; + else + precision = 0; + + if (plus) + NITF_SNPRINTF(fmt, 64, "%%+-1.%dl%s", precision, type); + else + NITF_SNPRINTF(fmt, 64, "%%-1.%dl%s", precision, type); + NITF_SNPRINTF(buffer, bufferLen + 1, fmt, value); + } + + if (!nitf_Field_setRawData(field, buffer, field->length, error)) + { + NITF_FREE(buffer); + return(NITF_FAILURE); + } + + NITF_FREE(buffer); + return(NITF_SUCCESS); +} + +/*! + * \fn nitf_Field_destruct + * \param field The field to dereference, deallocate, and NULL-set + * + * Destroy the field object, and NULL-set the pointer. This is why + * we require a reference to the object pointer. + */ +NITFAPI(void) nitf_Field_destruct(nitf_Field ** field) +{ + if (*field) + { + if ((*field)->raw) + { + NITF_FREE((*field)->raw); + (*field)->raw = NULL; + } + + NITF_FREE(*field); + *field = NULL; + } +} + + +/*! + * Clone this object. This is a deep copy operation. + * + * \param source The source object + * \param error An error to populate upon failure + * \return A new object that is identical to the old + */ +NITFAPI(nitf_Field *) nitf_Field_clone(nitf_Field * source, + nitf_Error * error) +{ + nitf_Field *field = NULL; + + if (source) + { + /* construct new one */ + field = nitf_Field_construct(source->length, source->type, error); + if (field) + { + field->resizable = source->resizable; + /* set the data */ + if (!nitf_Field_setRawData + (field, (NITF_DATA *) source->raw, source->length, error)) + { + nitf_Field_destruct(&field); + field = NULL; + } + } + } + return field; +} + + +NITFPRIV(NITF_BOOL) fromStringToString(nitf_Field * field, char *outValue, + size_t length, nitf_Error * error) +{ + if (length) + { + if (length == 1) + { + outValue[0] = 0; + } + else + { + size_t amount = (( length - 1 ) < field->length ) ? (length - 1) : (field->length); + memcpy(outValue, field->raw, amount); + outValue[amount] = 0; + } + } + return NITF_SUCCESS; +} + + +NITFPRIV(NITF_BOOL) toInt16(nitf_Field * field, nitf_Int16 * int16, + nitf_Error * error); +NITFPRIV(NITF_BOOL) toInt32(nitf_Field * field, nitf_Int32 * int32, + nitf_Error * error); +NITFPRIV(NITF_BOOL) toInt64(nitf_Field * field, nitf_Int64 * int64, + nitf_Error * error); +NITFPRIV(NITF_BOOL) toUint16(nitf_Field * field, nitf_Uint16 * int16, + nitf_Error * error); +NITFPRIV(NITF_BOOL) toUint32(nitf_Field * field, nitf_Uint32 * int32, + nitf_Error * error); +NITFPRIV(NITF_BOOL) toUint64(nitf_Field * field, nitf_Uint64 * int64, + nitf_Error * error); + +/* We may want to rethink this function a bit. + * The NITF spec. has many fields with a BINARY_INTEGER type + * This could mean that the field contains 3 8-bit binary integers + * For that example, the length of the field is 3, which isn't an integer size + * Thus, that wouldn't work here if we just assumed BINARY_INTEGER has ONE integer in the field + */ +NITFPRIV(NITF_BOOL) fromIntToString(nitf_Field * field, char *outValue, + size_t length, nitf_Error * error) +{ + char buffer[256]; + size_t actualLength = 0; + /* These are all two-step processes 1) get native int 2) NITF_SNPRINTF */ + switch (field->length) + { + case 2: + { + nitf_Int16 int16; + if (!toInt16(field, &int16, error)) + goto CATCH_ERROR; + actualLength = NITF_SNPRINTF(buffer, 256, "%d", int16); + } + break; + case 4: + { + nitf_Int32 int32; + if (!toInt32(field, &int32, error)) + goto CATCH_ERROR; + actualLength = NITF_SNPRINTF(buffer, 256, "%ld", (long) int32); + } + break; + case 8: + { + nitf_Int64 int64; + if (!toInt64(field, &int64, error)) + goto CATCH_ERROR; + actualLength = NITF_SNPRINTF(buffer, 256, "%lld", int64); + } + break; + default: + { + /* otherwise, it must not be an integer value */ + return fromStringToString(field, outValue, length, error); + } + } + if (actualLength > length) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_INVALID_PARAMETER, + "Out value too small [%d] size required", + strlen(buffer)); + return NITF_FAILURE; + } + strcpy(outValue, buffer); + return NITF_SUCCESS; + +CATCH_ERROR: + return NITF_FAILURE; +} + + +NITFPRIV(NITF_BOOL) toString(nitf_Field * field, char *outValue, + size_t length, nitf_Error * error) +{ + NITF_BOOL status = NITF_FAILURE; + switch (field->type) + { + case NITF_BCS_A: + case NITF_BCS_N: + status = fromStringToString(field, outValue, length, error); + break; + case NITF_BINARY: + status = fromIntToString(field, outValue, length, error); + break; + default: + nitf_Error_init(error, "Unknown conversion", NITF_CTXT, + NITF_ERR_INVALID_PARAMETER); + break; + } + return status; +} + + +NITFPRIV(NITF_BOOL) toRaw(nitf_Field * field, char *outValue, + size_t length, nitf_Error * error) +{ + NITF_BOOL status = NITF_SUCCESS; + if (length && length <= field->length) + { + memcpy(outValue, field->raw, length); + } + else + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_INVALID_PARAMETER, + "Length [%d] is longer than field width [%d]", + length, field->length); + status = NITF_FAILURE; + } + return status; +} + + +NITFPRIV(NITF_BOOL) toReal(nitf_Field * field, NITF_DATA * outData, + size_t length, nitf_Error * error) +{ + NITF_BOOL status = NITF_SUCCESS; + char* tmpBuf = NULL; + + switch (field->type) + { + case NITF_BCS_A: + case NITF_BCS_N: + tmpBuf = (char* )NITF_MALLOC(field->length + 1); + if (!tmpBuf) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + status = NITF_FAILURE; + break; + } + memcpy(tmpBuf, field->raw, field->length); + tmpBuf[field->length] = 0; + if (length == sizeof(float)) + *((float *) outData) = (float) atof(tmpBuf); + else if (length == sizeof(double)) + *((double *) outData) = (double) atof(tmpBuf); + else + { + nitf_Error_init(error, "toReal -> incorrect length", NITF_CTXT, + NITF_ERR_INVALID_PARAMETER); + status = NITF_FAILURE; + } + NITF_FREE(tmpBuf); + break; + case NITF_BINARY: + memcpy(outData, field->raw, length); + break; + default: + nitf_Error_init(error, "Unknown conversion", NITF_CTXT, + NITF_ERR_INVALID_PARAMETER); + status = NITF_FAILURE; + break; + } + + return status; +} + + +NITFPRIV(NITF_BOOL) toInt16(nitf_Field * field, nitf_Int16 * int16, + nitf_Error * error) +{ + *int16 = *((nitf_Int16 *) field->raw); + return NITF_SUCCESS; +} + + +NITFPRIV(NITF_BOOL) toInt32(nitf_Field * field, nitf_Int32 * int32, + nitf_Error * error) +{ + *int32 = *((nitf_Int32 *) field->raw); + return NITF_SUCCESS; +} + + +NITFPRIV(NITF_BOOL) toInt64(nitf_Field * field, nitf_Int64 * int64, + nitf_Error * error) +{ + *int64 = *((nitf_Int64 *) field->raw); + return NITF_SUCCESS; +} + + +NITFPRIV(NITF_BOOL) toUint16(nitf_Field * field, nitf_Uint16 * int16, + nitf_Error * error) +{ + *int16 = *((nitf_Uint16 *) field->raw); + return NITF_SUCCESS; +} + + +NITFPRIV(NITF_BOOL) toUint32(nitf_Field * field, nitf_Uint32 * int32, + nitf_Error * error) +{ + *int32 = *((nitf_Uint32 *) field->raw); + return NITF_SUCCESS; +} + + +NITFPRIV(NITF_BOOL) toUint64(nitf_Field * field, nitf_Uint64 * int64, + nitf_Error * error) +{ + *int64 = *((nitf_Uint64 *) field->raw); + return NITF_SUCCESS; +} + + +NITFPRIV(NITF_BOOL) fromStringToInt(nitf_Field * field, + NITF_DATA * outData, size_t length, + nitf_Error * error) +{ + char buffer[256]; + if (field->length > 256) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_INVALID_PARAMETER, + "Field length too long for string conversion [%d]", + field->length); + return NITF_FAILURE; + } + memcpy(buffer, field->raw, field->length); + buffer[field->length] = 0; + switch (length) + { + case 2: + { + nitf_Int16 *int16 = (nitf_Int16 *) outData; + *int16 = (nitf_Int16) NITF_ATO32(buffer); + } + break; + case 4: + { + nitf_Int32 *int32 = (nitf_Int32 *) outData; + *int32 = NITF_ATO32(buffer); + } + break; + case 8: + { + nitf_Int64 *int64 = (nitf_Int64 *) outData; +#if defined(__aix__) + sscanf(buffer, "%lld", int64); +#else + *int64 = NITF_ATO64(buffer); +#endif + } + break; + default: + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_INVALID_PARAMETER, + NITF_CTXT, "Unsupported length [%d]", length); + return NITF_FAILURE; + } + return NITF_SUCCESS; +} + + +NITFPRIV(NITF_BOOL) fromStringToUint(nitf_Field * field, + NITF_DATA * outData, size_t length, + nitf_Error * error) +{ + char buffer[256]; + if (field->length > 256) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_INVALID_PARAMETER, + "Field length too long for string conversion [%d]", + field->length); + return NITF_FAILURE; + } + memcpy(buffer, field->raw, field->length); + buffer[field->length] = 0; + switch (length) + { + case 2: + { + nitf_Uint16 *int16 = (nitf_Uint16 *) outData; + *int16 = (nitf_Uint16) NITF_ATO32(buffer); + } + break; + case 4: + { + nitf_Uint32 *int32 = (nitf_Uint32 *) outData; + *int32 = (nitf_Uint32) NITF_ATOU32(buffer); + } + break; + case 8: + { + nitf_Uint64 *int64 = (nitf_Uint64 *) outData; +#if defined(__aix__) + sscanf(buffer, "%lld", int64); +#else + *int64 = (nitf_Uint64) NITF_ATO64(buffer); +#endif + } + break; + default: + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_INVALID_PARAMETER, + "Unsupported length [%d]", length); + return NITF_FAILURE; + } + return NITF_SUCCESS; +} + + +NITFPRIV(NITF_BOOL) toInt(nitf_Field * field, + NITF_DATA * outData, + size_t length, nitf_Error * error) +{ + /* First we have to figure out what we are storing... + See, its okay to convert a BCS-N to an int, and... + its also okay to maintain a binary int... */ + NITF_BOOL status = NITF_FAILURE; + if (field->type == NITF_BINARY) + { + switch (field->length) + { + case 2: + status = toInt16(field, (nitf_Int16 *) outData, error); + break; + case 4: + status = toInt32(field, (nitf_Int32 *) outData, error); + break; + case 8: + status = toInt64(field, (nitf_Int64 *) outData, error); + break; + default: + nitf_Error_initf(error, NITF_CTXT, + NITF_ERR_INVALID_PARAMETER, + "Unexpected field size for int [%d]", + field->length); + } + } + else + { + status = fromStringToInt(field, outData, length, error); + } + return status; +} + + +NITFPRIV(NITF_BOOL) toUint(nitf_Field * field, + NITF_DATA * outData, + size_t length, nitf_Error * error) +{ + /* First we have to figure out what we are storing... + See, its okay to convert a BCS-N to an int, and... + its also okay to maintain a binary int... */ + NITF_BOOL status = NITF_FAILURE; + if (field->type == NITF_BINARY) + { + switch (field->length) + { + case 2: + status = toUint16(field, (nitf_Uint16 *) outData, error); + break; + case 4: + status = toUint32(field, (nitf_Uint32 *) outData, error); + break; + case 8: + status = toUint64(field, (nitf_Uint64 *) outData, error); + break; + default: + nitf_Error_initf(error, NITF_CTXT, + NITF_ERR_INVALID_PARAMETER, + "Unexpected field size for uint [%d]", + field->length); + } + } + else + { + status = fromStringToUint(field, outData, length, error); + } + return status; +} + + +NITFAPI(NITF_BOOL) nitf_Field_get(nitf_Field * field, + NITF_DATA * outValue, + nitf_ConvType convType, + size_t length, nitf_Error * error) +{ + NITF_BOOL status = NITF_FAILURE; + switch (convType) + { + case NITF_CONV_UINT: + status = toUint(field, outValue, length, error); + break; + + case NITF_CONV_INT: + status = toInt(field, outValue, length, error); + break; + + case NITF_CONV_STRING: + status = toString(field, (char *) outValue, length, error); + break; + + case NITF_CONV_RAW: + status = toRaw(field, (char *) outValue, length, error); + break; + + case NITF_CONV_REAL: + status = toReal(field, outValue, length, error); + break; + } + return status; +} + + +NITFPROT(NITF_BOOL) nitf_Field_resetLength(nitf_Field * field, + size_t newLength, + NITF_BOOL keepData, + nitf_Error * error) +{ + size_t diff; + size_t oldLength; + char *raw; + + if (newLength > 0) + { + /* remember old data */ + raw = field->raw; + + field->raw = (char *) NITF_MALLOC(newLength + 1); + if (!field->raw) + { + field->raw = raw; + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + return 0; + } + + field->raw[newLength] = 0; /* terminating null byte */ + oldLength = field->length; + field->length = newLength; + + /* ignore old data */ + if (!keepData) + { + if (field->type == NITF_BCS_N) + memset(field->raw, '0', newLength); + else if (field->type == NITF_BCS_A) + memset(field->raw, ' ', newLength); + else + memset(field->raw, 0, newLength); + } + /* copy the old data */ + else + { + diff = newLength - field->length; + if (field->type == NITF_BCS_N) + copyAndFillZeros(field, raw, + diff < 0 ? newLength : oldLength, error); + else if (field->type == NITF_BCS_A) + copyAndFillSpaces(field, raw, + diff < 0 ? newLength : oldLength, error); + else + { + memset(field->raw, 0, newLength); + memcpy(field->raw, raw, diff < 0 ? newLength : oldLength); + } + } + + /* free the old memory */ + NITF_FREE(raw); + } + else + { + nitf_Error_initf(error, + NITF_CTXT, + NITF_ERR_INVALID_PARAMETER, + "Invalid length specified"); + return 0; + } + return 1; +} + + +NITFPROT(void) nitf_Field_print(nitf_Field * field) +{ + if (!field || field->length <= 0) + return; + + switch (field->type) + { + case NITF_BINARY: + /* avoid printing binary */ + printf("", field->length); + break; + + case NITF_BCS_N: + case NITF_BCS_A: + printf("%.*s", (int)field->length, field->raw); + break; + default: + printf("Invalid Field type [%d]\n", (int) field->type); + } +} + + +NITFAPI(NITF_BOOL) nitf_Field_resizeField(nitf_Field *field, + size_t newLength, + nitf_Error *error) +{ + char fill = 0; + + /* it must be resizable */ + if (!field->resizable) + return NITF_FAILURE; + + if (field && newLength != field->length) + { + if (field->raw) + NITF_FREE(field->raw); + + field->raw = NULL; + + /* re-malloc */ + field->raw = (char *) NITF_MALLOC(newLength + 1); + if (!field->raw) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + goto CATCH_ERROR; + } + + /* set the new length */ + field->length = newLength; + + field->raw[newLength] = 0; /* terminating null byte */ + switch (field->type) + { + case NITF_BCS_A: + fill = ' '; + break; + case NITF_BCS_N: + fill = '0'; + break; + case NITF_BINARY: + fill = 0; + break; + default: + nitf_Error_initf(error, NITF_CTXT, + NITF_ERR_INVALID_PARAMETER, + "Invalid type [%d]", field->type); + goto CATCH_ERROR; + } + + memset(field->raw, fill, field->length); + } + + return NITF_SUCCESS; + + CATCH_ERROR: + return NITF_FAILURE; +} + + +/* + * Private function to check that a string is BCS_N. + * + * A zero length string passes + */ + +NITFPRIV(NITF_BOOL) isBCSN(const char *str, nitf_Uint32 len, nitf_Error * error) +{ + char *strp; /* Pointer into string */ + nitf_Uint32 i; + + strp = (char*)str; + + /* Look for + or minus which must be the first character */ + + if ((*strp == '+') || (*strp == '-')) + { + strp += 1; + len -= 1; + } + + for (i = 0; i < len; i++) + { + /* + * Some TRE's allow for all minus signs to represent + * BCSN if number not known (e.g. BANDSB) + */ + if (!isdigit(*strp) && (*strp != '-')) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_INVALID_PARAMETER, + "Invalid character %c in BCS_N string", + *strp); + return (NITF_FAILURE); + } + strp += 1; + } + + return (NITF_SUCCESS); +} + + +/* + * Private function to check that a string is BCS_A. + * + * A zero length string passes + */ + +NITFPRIV(NITF_BOOL) isBCSA(const char *str, nitf_Uint32 len, nitf_Error * error) +{ + nitf_Uint8 *strp; /* Pointer into string */ + nitf_Uint32 i; + + strp = (nitf_Uint8 *) str; + + for (i = 0; i < len; i++) + { + if ((*strp < 0x20) || (*strp > 0x7e)) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_INVALID_PARAMETER, + "Invalid character %c in BCS_N string", + *strp); + return (NITF_FAILURE); + } + strp += 1; + } + + return (NITF_SUCCESS); +} diff --git a/modules/c/nitf/source/FieldWarning.c b/modules/c/nitf/source/FieldWarning.c new file mode 100644 index 000000000..689c57d70 --- /dev/null +++ b/modules/c/nitf/source/FieldWarning.c @@ -0,0 +1,208 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/FieldWarning.h" + +/*! + * Construct a FieldWarning object + * This function creates a FieldWarning object. + * \param fileOffset Offset in the file to the field + * \param field A string which represents the NITF field + * \param value The NITF field value + * \param expectation A string describing the expected field value + * \param error An error object to fill if a problem occurs + * \return A FieldWarning object or NULL upon failure + */ +NITFAPI(nitf_FieldWarning *) nitf_FieldWarning_construct(nitf_Off fileOffset, + const char *fieldName, + nitf_Field *field, + const char + *expectation, + nitf_Error * + error) +{ + nitf_FieldWarning *result; /* Return value */ + size_t strLength; /* Length of a string in bytes */ + + /* Get some memory */ + result = (nitf_FieldWarning *) NITF_MALLOC(sizeof(nitf_FieldWarning)); + + /* If we couldn't get memory */ + if (!result) + { + nitf_Error_init(error, + NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + return NULL; + } + + if (field) + { + result->field = nitf_Field_clone(field, error); + if (!(result->field)) + { + NITF_FREE(result); + return NULL; + } + } + else + { + result->field = NULL; + } + + /* fileOffset */ + result->fileOffset = fileOffset; + + /* set these to be safe */ + result->fieldName = NULL; + result->expectation = NULL; + + /* field */ + if (fieldName) + { + strLength = strlen(fieldName); + result->fieldName = (char *) NITF_MALLOC(strLength + 1); + strcpy(result->fieldName, fieldName); + result->fieldName[strLength] = 0; + } + + /* expectation */ + if (expectation) + { + strLength = strlen(expectation); + result->expectation = (char *) NITF_MALLOC(strLength + 1); + strcpy(result->expectation, expectation); + result->expectation[strLength] = 0; + } + + return result; +} + + +/*! + * Destruct a FieldWarning object + * This function destructs a FieldWarning object and NULL sets its pointer + * \param fieldWarningPtr A pointer to a FieldWarning object + */ +NITFAPI(void) nitf_FieldWarning_destruct(nitf_FieldWarning ** + fieldWarningPtr) +{ + if (!(*fieldWarningPtr)) + { + return; /* Yeah, Yeah, one entrance one ... */ + } + + if ((*fieldWarningPtr)->fieldName) + { + NITF_FREE((*fieldWarningPtr)->fieldName); + } + + if ((*fieldWarningPtr)->field) + { + nitf_Field_destruct(&((*fieldWarningPtr)->field)); + } + + if ((*fieldWarningPtr)->expectation) + { + NITF_FREE((*fieldWarningPtr)->expectation); + } + + NITF_FREE(*fieldWarningPtr); + *fieldWarningPtr = NULL; + + return; +} + + +/*! + * Clone a FieldWarning object + * This function clones (deep copies) a FieldWarning object + * \param source The source object + * \param error An error object to fill if a problem occurs + * \return A FieldWarning object or NULL upon failure + */ +NITFAPI(nitf_FieldWarning *) nitf_FieldWarning_clone(nitf_FieldWarning * + source, + nitf_Error * error) +{ + nitf_FieldWarning *result; /* Return value */ + size_t strLength; /* Length of a string in bytes */ + + if (!source) + { + nitf_Error_initf(error, + NITF_CTXT, + NITF_ERR_INVALID_OBJECT, + "Trying to clone NULL pointer"); + return NULL; + } + + /* Get some memory */ + result = (nitf_FieldWarning *) NITF_MALLOC(sizeof(nitf_FieldWarning)); + + /* If we couldn't get memory */ + if (!result) + { + nitf_Error_init(error, + NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + return NULL; + } + + result->fileOffset = source->fileOffset; + result->field = NULL; + result->fieldName = NULL; + result->expectation = NULL; + + /* expectation */ + if (source->expectation) + { + strLength = strlen(source->expectation); + result->expectation = (char *) NITF_MALLOC(strLength + 1); + strcpy(result->expectation, source->expectation); + result->expectation[strLength] = 0; + } + + /* fieldName */ + if (source->fieldName) + { + result->fieldName = (char *) NITF_MALLOC(strlen(source->fieldName) + 1); + if (!result->fieldName) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + goto CATCH_ERROR; + + } + strcpy(result->fieldName, source->fieldName); + result->fieldName[strlen(source->fieldName)] = 0; + } + + /* field */ + result->field = nitf_Field_clone(source->field, error); + + return result; + +CATCH_ERROR: + nitf_FieldWarning_destruct(&result); + return NULL; +} diff --git a/modules/c/nitf/source/FileHeader.c b/modules/c/nitf/source/FileHeader.c new file mode 100644 index 000000000..18825079e --- /dev/null +++ b/modules/c/nitf/source/FileHeader.c @@ -0,0 +1,476 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/FileHeader.h" + +#define _NITF_CONSTRUCT_FIELD(OWNER, ID, TYPE) \ + OWNER->ID = nitf_Field_construct(ID##_SZ, TYPE, error); \ + if (!OWNER->ID) goto CATCH_ERROR; + +#define _NITF_CLONE_FIELD(DEST, SOURCE, ID) \ + DEST->ID = nitf_Field_clone(SOURCE->ID, error); \ + if (!DEST->ID) goto CATCH_ERROR; + +#define _NITF_DESTRUCT_FIELD(OWNER, ID) \ + if (OWNER->ID) nitf_Field_destruct(OWNER->ID); + +NITFAPI(nitf_FileHeader *) nitf_FileHeader_construct(nitf_Error * error) +{ + /* Start by allocating the header */ + nitf_FileHeader *header = (nitf_FileHeader *) + NITF_MALLOC(sizeof(nitf_FileHeader)); + + /* Return now if we have a problem above */ + if (!header) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + + goto CATCH_ERROR; + } + /* First, we initialize all of our sections to NULL */ + /* This will prevent problems when we allocate them */ + header->imageInfo = NULL; + header->graphicInfo = NULL; + header->labelInfo = NULL; + header->textInfo = NULL; + header->dataExtensionInfo = NULL; + header->reservedExtensionInfo = NULL; + header->securityGroup = NULL; + header->userDefinedSection = NULL; + header->extendedSection = NULL; + + header->securityGroup = nitf_FileSecurity_construct(error); + if (!header->securityGroup) + goto CATCH_ERROR; + + /* Zero out a known block of memory, by ID */ + _NITF_CONSTRUCT_FIELD(header, NITF_FHDR, NITF_BCS_A); + + _NITF_CONSTRUCT_FIELD(header, NITF_FVER, NITF_BCS_A); + _NITF_CONSTRUCT_FIELD(header, NITF_CLEVEL, NITF_BCS_N); + _NITF_CONSTRUCT_FIELD(header, NITF_STYPE, NITF_BCS_A); + _NITF_CONSTRUCT_FIELD(header, NITF_OSTAID, NITF_BCS_A); + _NITF_CONSTRUCT_FIELD(header, NITF_FDT, NITF_BCS_A); + _NITF_CONSTRUCT_FIELD(header, NITF_FTITLE, NITF_BCS_A); + _NITF_CONSTRUCT_FIELD(header, NITF_FSCLAS, NITF_BCS_A); + + _NITF_CONSTRUCT_FIELD(header, NITF_FSCOP, NITF_BCS_N); + _NITF_CONSTRUCT_FIELD(header, NITF_FSCPYS, NITF_BCS_N); + _NITF_CONSTRUCT_FIELD(header, NITF_ENCRYP, NITF_BCS_A); + _NITF_CONSTRUCT_FIELD(header, NITF_FBKGC, NITF_BINARY); + _NITF_CONSTRUCT_FIELD(header, NITF_ONAME, NITF_BCS_A); + _NITF_CONSTRUCT_FIELD(header, NITF_OPHONE, NITF_BCS_A); + + _NITF_CONSTRUCT_FIELD(header, NITF_FL, NITF_BCS_N); + _NITF_CONSTRUCT_FIELD(header, NITF_HL, NITF_BCS_N); + _NITF_CONSTRUCT_FIELD(header, NITF_NUMI, NITF_BCS_N); + _NITF_CONSTRUCT_FIELD(header, NITF_NUMS, NITF_BCS_N); + _NITF_CONSTRUCT_FIELD(header, NITF_NUMX, NITF_BCS_N); + _NITF_CONSTRUCT_FIELD(header, NITF_NUMT, NITF_BCS_N); + _NITF_CONSTRUCT_FIELD(header, NITF_NUMDES, NITF_BCS_N); + _NITF_CONSTRUCT_FIELD(header, NITF_NUMRES, NITF_BCS_N); + + _NITF_CONSTRUCT_FIELD(header, NITF_UDHDL, NITF_BCS_N); + _NITF_CONSTRUCT_FIELD(header, NITF_UDHOFL, NITF_BCS_N); + _NITF_CONSTRUCT_FIELD(header, NITF_XHDL, NITF_BCS_N); + _NITF_CONSTRUCT_FIELD(header, NITF_XHDLOFL, NITF_BCS_N); + + + header->userDefinedSection = nitf_Extensions_construct(error); + if (!header->userDefinedSection) + goto CATCH_ERROR; + header->extendedSection = nitf_Extensions_construct(error); + if (!header->extendedSection) + goto CATCH_ERROR; + + return header; + +CATCH_ERROR: + /* destruct if it was allocated */ + if (header) + nitf_FileHeader_destruct(&header); + return NULL; +} + + +NITFAPI(nitf_FileHeader *) nitf_FileHeader_clone(nitf_FileHeader * source, + nitf_Error * error) +{ + nitf_Uint32 numImages, numGraphics, numLabels; + nitf_Uint32 numTexts, numDES, numRES; + nitf_Uint32 i; + + /* Start with a NULL pointer */ + nitf_FileHeader *header = NULL; + if (source) + { + /* Start by allocating the header */ + header = (nitf_FileHeader *) NITF_MALLOC(sizeof(nitf_FileHeader)); + if (!header) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + return NULL; + } + + header->securityGroup = + nitf_FileSecurity_clone(source->securityGroup, error); + + header->imageInfo = NULL; + header->graphicInfo = NULL; + header->labelInfo = NULL; + header->textInfo = NULL; + header->dataExtensionInfo = NULL; + header->reservedExtensionInfo = NULL; + + /* These objects all start out NULL, */ + /* and if they arent assigned, they remain NULL */ + /* This poses a problem when we clone, so for now, */ + /* Im checking to make sure I have something to */ + /* clone in the first place. */ + + NITF_TRY_GET_UINT32(source->numImages, &numImages, error); + NITF_TRY_GET_UINT32(source->numGraphics, &numGraphics, error); + NITF_TRY_GET_UINT32(source->numLabels, &numLabels, error); + NITF_TRY_GET_UINT32(source->numTexts, &numTexts, error); + NITF_TRY_GET_UINT32(source->numDataExtensions, &numDES, error); + NITF_TRY_GET_UINT32(source->numReservedExtensions, &numRES, error); + + if (numImages > 0) + { + header->imageInfo = + (nitf_ComponentInfo **) + NITF_MALLOC(sizeof(nitf_ComponentInfo *) * numImages); + + if (!header->imageInfo) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + goto CATCH_ERROR; + } + + for (i = 0; i < numImages; ++i) + { + header->imageInfo[i] = + nitf_ComponentInfo_clone(source->imageInfo[i], error); + if (!header->imageInfo[i]) + goto CATCH_ERROR; + } + } + + if (numGraphics > 0) + { + header->graphicInfo = + (nitf_ComponentInfo **) + NITF_MALLOC(sizeof(nitf_ComponentInfo *) * numGraphics); + + if (!header->graphicInfo) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + goto CATCH_ERROR; + } + + for (i = 0; i < numGraphics; ++i) + { + header->graphicInfo[i] = + nitf_ComponentInfo_clone(source->graphicInfo[i], + error); + if (!header->graphicInfo[i]) + goto CATCH_ERROR; + } + } + + if (numLabels > 0) + { + header->labelInfo = + (nitf_ComponentInfo **) + NITF_MALLOC(sizeof(nitf_ComponentInfo *) * numLabels); + + if (!header->labelInfo) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + goto CATCH_ERROR; + } + + for (i = 0; i < numLabels; ++i) + { + header->labelInfo[i] = + nitf_ComponentInfo_clone(source->labelInfo[i], error); + if (!header->labelInfo[i]) + goto CATCH_ERROR; + } + } + + if (numTexts > 0) + { + header->textInfo = + (nitf_ComponentInfo **) + NITF_MALLOC(sizeof(nitf_ComponentInfo *) * numTexts); + + if (!header->textInfo) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + goto CATCH_ERROR; + } + + for (i = 0; i < numTexts; ++i) + { + header->textInfo[i] = + nitf_ComponentInfo_clone(source->textInfo[i], error); + if (!header->textInfo[i]) + goto CATCH_ERROR; + } + } + + if (numDES > 0) + { + header->dataExtensionInfo = + (nitf_ComponentInfo **) + NITF_MALLOC(sizeof(nitf_ComponentInfo *) * numDES); + + if (!header->dataExtensionInfo) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + goto CATCH_ERROR; + } + + for (i = 0; i < numDES; ++i) + { + header->dataExtensionInfo[i] = + nitf_ComponentInfo_clone(source->dataExtensionInfo[i], + error); + if (!header->dataExtensionInfo[i]) + goto CATCH_ERROR; + } + } + + if (numRES > 0) + { + header->reservedExtensionInfo = + (nitf_ComponentInfo **) + NITF_MALLOC(sizeof(nitf_ComponentInfo *) * numRES); + + if (!header->dataExtensionInfo) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + goto CATCH_ERROR; + } + + for (i = 0; i < numRES; ++i) + { + header->reservedExtensionInfo[i] = + nitf_ComponentInfo_clone(source-> + reservedExtensionInfo[i], + error); + if (!header->reservedExtensionInfo[i]) + goto CATCH_ERROR; + } + } + + /* init these to NULL for safety */ + header->userDefinedSection = NULL; + header->extendedSection = NULL; + + /* Copy over extension segments */ + if (source->userDefinedSection) + { + header->userDefinedSection = + nitf_Extensions_clone(source->userDefinedSection, error); + if (!header->userDefinedSection) + goto CATCH_ERROR; + } + + if (source->extendedSection) + { + header->extendedSection = + nitf_Extensions_clone(source->extendedSection, error); + if (!header->extendedSection) + goto CATCH_ERROR; + } + + /* Copy a known block of memory, by ID */ + _NITF_CLONE_FIELD(header, source, NITF_FHDR); + + _NITF_CLONE_FIELD(header, source, NITF_FVER); + _NITF_CLONE_FIELD(header, source, NITF_CLEVEL); + _NITF_CLONE_FIELD(header, source, NITF_STYPE); + _NITF_CLONE_FIELD(header, source, NITF_OSTAID); + _NITF_CLONE_FIELD(header, source, NITF_FDT); + _NITF_CLONE_FIELD(header, source, NITF_FTITLE); + _NITF_CLONE_FIELD(header, source, NITF_FSCLAS); + + _NITF_CLONE_FIELD(header, source, NITF_FSCOP); + _NITF_CLONE_FIELD(header, source, NITF_FSCPYS); + _NITF_CLONE_FIELD(header, source, NITF_ENCRYP); + _NITF_CLONE_FIELD(header, source, NITF_FBKGC); + _NITF_CLONE_FIELD(header, source, NITF_ONAME); + _NITF_CLONE_FIELD(header, source, NITF_OPHONE); + + /* Now copy the value fields */ + _NITF_CLONE_FIELD(header, source, NITF_FL); + _NITF_CLONE_FIELD(header, source, NITF_HL); + _NITF_CLONE_FIELD(header, source, NITF_NUMI); + _NITF_CLONE_FIELD(header, source, NITF_NUMS); + _NITF_CLONE_FIELD(header, source, NITF_NUMX); + _NITF_CLONE_FIELD(header, source, NITF_NUMT); + _NITF_CLONE_FIELD(header, source, NITF_NUMDES); + _NITF_CLONE_FIELD(header, source, NITF_NUMRES); + + _NITF_CLONE_FIELD(header, source, NITF_UDHDL); + _NITF_CLONE_FIELD(header, source, NITF_UDHOFL); + _NITF_CLONE_FIELD(header, source, NITF_XHDL); + _NITF_CLONE_FIELD(header, source, NITF_XHDLOFL); + + /* Return the cloned header */ + return header; + } + +CATCH_ERROR: + nitf_FileHeader_destruct(&header); + return NULL; +} + + +/* + * Destruct all sub-objects, and make sure that we + * kill this object too. + */ +NITFAPI(void) nitf_FileHeader_destruct(nitf_FileHeader ** fh) +{ + nitf_Uint32 numImages, numGraphics, numLabels; + nitf_Uint32 numTexts, numDES, numRES; + nitf_Uint32 i; + + nitf_Error error; + + if (!*fh) + return; + + if ((*fh)->userDefinedSection) + nitf_Extensions_destruct(&(*fh)->userDefinedSection); + + if ((*fh)->extendedSection) + nitf_Extensions_destruct(&(*fh)->extendedSection); + + NITF_TRY_GET_UINT32((*fh)->numImages, &numImages, &error); + NITF_TRY_GET_UINT32((*fh)->numGraphics, &numGraphics, &error); + NITF_TRY_GET_UINT32((*fh)->numLabels, &numLabels, &error); + NITF_TRY_GET_UINT32((*fh)->numTexts, &numTexts, &error); + NITF_TRY_GET_UINT32((*fh)->numDataExtensions, &numDES, &error); + NITF_TRY_GET_UINT32((*fh)->numReservedExtensions, &numRES, &error); + + /* need this for the above calls */ +CATCH_ERROR: + + for (i = 0; i < numImages && (*fh)->imageInfo; ++i) + nitf_ComponentInfo_destruct(&(*fh)->imageInfo[i]); + + for (i = 0; i < numGraphics && (*fh)->graphicInfo; ++i) + nitf_ComponentInfo_destruct(&(*fh)->graphicInfo[i]); + + for (i = 0; i < numLabels && (*fh)->labelInfo; ++i) + nitf_ComponentInfo_destruct(&(*fh)->labelInfo[i]); + + for (i = 0; i < numTexts && (*fh)->textInfo; ++i) + nitf_ComponentInfo_destruct(&(*fh)->textInfo[i]); + + for (i = 0; i < numDES && (*fh)->dataExtensionInfo; ++i) + nitf_ComponentInfo_destruct(&(*fh)->dataExtensionInfo[i]); + + for (i = 0; i < numRES && (*fh)->reservedExtensionInfo; ++i) + nitf_ComponentInfo_destruct(&(*fh)->reservedExtensionInfo[i]); + + if ((*fh)->imageInfo) + { + NITF_FREE((*fh)->imageInfo); + (*fh)->imageInfo = NULL; + } + if ((*fh)->graphicInfo) + { + NITF_FREE((*fh)->graphicInfo); + (*fh)->graphicInfo = NULL; + } + + if ((*fh)->labelInfo) + { + NITF_FREE((*fh)->labelInfo); + (*fh)->labelInfo = NULL; + } + + if ((*fh)->textInfo) + { + NITF_FREE((*fh)->textInfo); + (*fh)->textInfo = NULL; + } + if ((*fh)->dataExtensionInfo) + { + NITF_FREE((*fh)->dataExtensionInfo); + (*fh)->dataExtensionInfo = NULL; + } + if ((*fh)->reservedExtensionInfo) + { + NITF_FREE((*fh)->reservedExtensionInfo); + (*fh)->reservedExtensionInfo = NULL; + } + if ((*fh)->securityGroup) + { + nitf_FileSecurity_destruct(&(*fh)->securityGroup); + (*fh)->securityGroup = NULL; + } + + _NITF_DESTRUCT_FIELD(&(*fh), NITF_FHDR); + _NITF_DESTRUCT_FIELD(&(*fh), NITF_FVER); + _NITF_DESTRUCT_FIELD(&(*fh), NITF_CLEVEL); + _NITF_DESTRUCT_FIELD(&(*fh), NITF_STYPE); + _NITF_DESTRUCT_FIELD(&(*fh), NITF_OSTAID); + _NITF_DESTRUCT_FIELD(&(*fh), NITF_FDT); + _NITF_DESTRUCT_FIELD(&(*fh), NITF_FTITLE); + _NITF_DESTRUCT_FIELD(&(*fh), NITF_FSCLAS); + _NITF_DESTRUCT_FIELD(&(*fh), NITF_FSCOP); + _NITF_DESTRUCT_FIELD(&(*fh), NITF_FSCPYS); + _NITF_DESTRUCT_FIELD(&(*fh), NITF_ENCRYP); + _NITF_DESTRUCT_FIELD(&(*fh), NITF_FBKGC); + _NITF_DESTRUCT_FIELD(&(*fh), NITF_ONAME); + _NITF_DESTRUCT_FIELD(&(*fh), NITF_OPHONE); + _NITF_DESTRUCT_FIELD(&(*fh), NITF_FL); + _NITF_DESTRUCT_FIELD(&(*fh), NITF_HL); + _NITF_DESTRUCT_FIELD(&(*fh), NITF_NUMI); + _NITF_DESTRUCT_FIELD(&(*fh), NITF_NUMS); + _NITF_DESTRUCT_FIELD(&(*fh), NITF_NUMX); + _NITF_DESTRUCT_FIELD(&(*fh), NITF_NUMT); + _NITF_DESTRUCT_FIELD(&(*fh), NITF_NUMDES); + _NITF_DESTRUCT_FIELD(&(*fh), NITF_NUMRES); + _NITF_DESTRUCT_FIELD(&(*fh), NITF_UDHDL); + _NITF_DESTRUCT_FIELD(&(*fh), NITF_UDHOFL); + _NITF_DESTRUCT_FIELD(&(*fh), NITF_XHDL); + _NITF_DESTRUCT_FIELD(&(*fh), NITF_XHDLOFL); + + NITF_FREE(*fh); + *fh = NULL; +} + diff --git a/modules/c/nitf/source/FileSecurity.c b/modules/c/nitf/source/FileSecurity.c new file mode 100644 index 000000000..2f598b231 --- /dev/null +++ b/modules/c/nitf/source/FileSecurity.c @@ -0,0 +1,192 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/FileSecurity.h" + +#define _NITF_CONSTRUCT_FIELD(OWNER, ID, TYPE) \ + OWNER->ID = nitf_Field_construct(ID##_SZ, TYPE, error); \ + if (!OWNER->ID) goto CATCH_ERROR; + +#define _NITF_CLONE_FIELD(DEST, SOURCE, ID) \ + DEST->ID = nitf_Field_clone(SOURCE->ID, error); \ + if (!DEST->ID) goto CATCH_ERROR; + +#define _NITF_DESTRUCT_FIELD(OWNER, ID) \ + if (OWNER->ID) nitf_Field_destruct(OWNER->ID); + +#define _NITF_RESIZE_FIELD(field_, length_) \ + if (!nitf_Field_resetLength(field_, length_, 0, error)) goto CATCH_ERROR; + +/* + * Create this object and memset components to zero. + * + */ +NITFAPI(nitf_FileSecurity *) nitf_FileSecurity_construct(nitf_Error * + error) +{ + nitf_FileSecurity *fs = + (nitf_FileSecurity *) NITF_MALLOC(sizeof(nitf_FileSecurity)); + if (!fs) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + + goto CATCH_ERROR; + } + + _NITF_CONSTRUCT_FIELD(fs, NITF_CLSY, NITF_BCS_A); + _NITF_CONSTRUCT_FIELD(fs, NITF_CODE, NITF_BCS_A); + _NITF_CONSTRUCT_FIELD(fs, NITF_CTLH, NITF_BCS_A); + _NITF_CONSTRUCT_FIELD(fs, NITF_REL, NITF_BCS_A); + _NITF_CONSTRUCT_FIELD(fs, NITF_DCTP, NITF_BCS_A); + _NITF_CONSTRUCT_FIELD(fs, NITF_DCDT, NITF_BCS_A); + _NITF_CONSTRUCT_FIELD(fs, NITF_DCXM, NITF_BCS_A); + _NITF_CONSTRUCT_FIELD(fs, NITF_DG, NITF_BCS_A); + _NITF_CONSTRUCT_FIELD(fs, NITF_DGDT, NITF_BCS_A); + _NITF_CONSTRUCT_FIELD(fs, NITF_CLTX, NITF_BCS_A); + _NITF_CONSTRUCT_FIELD(fs, NITF_CATP, NITF_BCS_A); + _NITF_CONSTRUCT_FIELD(fs, NITF_CAUT, NITF_BCS_A); + _NITF_CONSTRUCT_FIELD(fs, NITF_CRSN, NITF_BCS_A); + _NITF_CONSTRUCT_FIELD(fs, NITF_RDT, NITF_BCS_A); + _NITF_CONSTRUCT_FIELD(fs, NITF_CTLN, NITF_BCS_A); + + return fs; + +CATCH_ERROR: + /* destruct if it was allocated */ + if (fs) + nitf_FileSecurity_destruct(&fs); + return NULL; +} + + +NITFAPI(NITF_BOOL) nitf_FileSecurity_resizeForVersion +(nitf_FileSecurity * fs, nitf_Version ver, nitf_Error * error) +{ + if (ver == NITF_VER_20) + { + _NITF_RESIZE_FIELD(fs->NITF_CODE, NITF_CODE_20_SZ); + _NITF_RESIZE_FIELD(fs->NITF_CTLH, NITF_CTLH_20_SZ); + _NITF_RESIZE_FIELD(fs->NITF_REL, NITF_REL_20_SZ); + _NITF_RESIZE_FIELD(fs->NITF_CAUT, NITF_CAUT_20_SZ); + _NITF_RESIZE_FIELD(fs->NITF_CTLN, NITF_CTLN_20_SZ); + _NITF_RESIZE_FIELD(fs->NITF_DGDT, NITF_DGDT_20_SZ); + _NITF_RESIZE_FIELD(fs->NITF_CLTX, NITF_CLTX_20_SZ); + } + /* otherwise, do 2.1... */ + else + { + _NITF_RESIZE_FIELD(fs->NITF_CODE, NITF_CODE_SZ); + _NITF_RESIZE_FIELD(fs->NITF_CTLH, NITF_CTLH_SZ); + _NITF_RESIZE_FIELD(fs->NITF_REL, NITF_REL_SZ); + _NITF_RESIZE_FIELD(fs->NITF_CAUT, NITF_CAUT_SZ); + _NITF_RESIZE_FIELD(fs->NITF_CTLN, NITF_CTLN_SZ); + _NITF_RESIZE_FIELD(fs->NITF_DGDT, NITF_DGDT_SZ); + _NITF_RESIZE_FIELD(fs->NITF_CLTX, NITF_CLTX_SZ); + } + + return NITF_SUCCESS; + +CATCH_ERROR: + return NITF_FAILURE; +} + + +NITFAPI(nitf_FileSecurity *) nitf_FileSecurity_clone(nitf_FileSecurity * + source, + nitf_Error * error) +{ + /* In this case, the cheapest is to */ + /* duplicate the constructor here... */ + nitf_FileSecurity *fs = NULL; + if (source) + { + fs = (nitf_FileSecurity *) NITF_MALLOC(sizeof(nitf_FileSecurity)); + if (!fs) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + + goto CATCH_ERROR; + + } + /* ...and copy here instead of memsets */ + _NITF_CLONE_FIELD(fs, source, NITF_CLSY); + _NITF_CLONE_FIELD(fs, source, NITF_CODE); + _NITF_CLONE_FIELD(fs, source, NITF_CTLH); + _NITF_CLONE_FIELD(fs, source, NITF_REL); + _NITF_CLONE_FIELD(fs, source, NITF_DCTP); + _NITF_CLONE_FIELD(fs, source, NITF_DCDT); + _NITF_CLONE_FIELD(fs, source, NITF_DCXM); + _NITF_CLONE_FIELD(fs, source, NITF_DG); + _NITF_CLONE_FIELD(fs, source, NITF_DGDT); + _NITF_CLONE_FIELD(fs, source, NITF_CLTX); + _NITF_CLONE_FIELD(fs, source, NITF_CATP); + _NITF_CLONE_FIELD(fs, source, NITF_CAUT); + _NITF_CLONE_FIELD(fs, source, NITF_CRSN); + _NITF_CLONE_FIELD(fs, source, NITF_RDT); + _NITF_CLONE_FIELD(fs, source, NITF_CTLN); + } + else + { + nitf_Error_initf(error, + NITF_CTXT, + NITF_ERR_INVALID_OBJECT, + "Trying to clone NULL pointer"); + } + return fs; + +CATCH_ERROR: + return NULL; +} + + +/*! + * Delete this object and null it. + * + * \param mem The memory object + * \return the object + */ +NITFAPI(void) nitf_FileSecurity_destruct(nitf_FileSecurity ** fs) +{ + if (!fs) + return; + + _NITF_DESTRUCT_FIELD(&(*fs), NITF_CLSY); + _NITF_DESTRUCT_FIELD(&(*fs), NITF_CODE); + _NITF_DESTRUCT_FIELD(&(*fs), NITF_CTLH); + _NITF_DESTRUCT_FIELD(&(*fs), NITF_REL); + _NITF_DESTRUCT_FIELD(&(*fs), NITF_DCTP); + _NITF_DESTRUCT_FIELD(&(*fs), NITF_DCDT); + _NITF_DESTRUCT_FIELD(&(*fs), NITF_DCXM); + _NITF_DESTRUCT_FIELD(&(*fs), NITF_DG); + _NITF_DESTRUCT_FIELD(&(*fs), NITF_DGDT); + _NITF_DESTRUCT_FIELD(&(*fs), NITF_CLTX); + _NITF_DESTRUCT_FIELD(&(*fs), NITF_CATP); + _NITF_DESTRUCT_FIELD(&(*fs), NITF_CAUT); + _NITF_DESTRUCT_FIELD(&(*fs), NITF_CRSN); + _NITF_DESTRUCT_FIELD(&(*fs), NITF_RDT); + _NITF_DESTRUCT_FIELD(&(*fs), NITF_CTLN); + + NITF_FREE(*fs); + *fs = NULL; +} diff --git a/modules/c/nitf/source/GraphicSegment.c b/modules/c/nitf/source/GraphicSegment.c new file mode 100644 index 000000000..3cd0426d7 --- /dev/null +++ b/modules/c/nitf/source/GraphicSegment.c @@ -0,0 +1,112 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/GraphicSegment.h" + +NITFAPI(nitf_GraphicSegment *) nitf_GraphicSegment_construct(nitf_Error * + error) +{ + nitf_GraphicSegment *segment = + (nitf_GraphicSegment *) NITF_MALLOC(sizeof(nitf_GraphicSegment)); + + if (!segment) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + return NULL; + } + + /* The graphic offset in the file */ + segment->offset = 0; + /* The graphic end (offset + length graphic) */ + segment->end = 0; + + /* This object gets created NOW */ + segment->subheader = NULL; + segment->subheader = nitf_GraphicSubheader_construct(error); + if (!segment->subheader) + { + nitf_GraphicSegment_destruct(&segment); + return NULL; + } + /* Yes! We have a success */ + return segment; +} + + +NITFAPI(nitf_GraphicSegment *) +nitf_GraphicSegment_clone(nitf_GraphicSegment * source, nitf_Error * error) +{ + nitf_GraphicSegment *segment = NULL; + + if (source) + { + segment = + (nitf_GraphicSegment *) + NITF_MALLOC(sizeof(nitf_GraphicSegment)); + + if (!segment) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + return NULL; + } + /* The graphic offset in the file */ + segment->offset = source->offset; + /* The graphic end (offset + length graphic) */ + segment->end = source->end; + + /* Just in case we self-destruct */ + segment->subheader = NULL; + segment->subheader = + nitf_GraphicSubheader_clone(source->subheader, error); + if (!segment->subheader) + { + nitf_GraphicSegment_destruct(&segment); + return NULL; + } + } + else + { + nitf_Error_initf(error, + NITF_CTXT, + NITF_ERR_INVALID_OBJECT, + "Trying to clone NULL pointer"); + } + /* Yes! We have a success */ + return segment; +} + + +NITFAPI(void) nitf_GraphicSegment_destruct(nitf_GraphicSegment ** segment) +{ + if (*segment) + { + if ((*segment)->subheader) + { + /* Destroy subheader info */ + nitf_GraphicSubheader_destruct(&(*segment)->subheader); + } + } + NITF_FREE(*segment); + *segment = NULL; +} diff --git a/modules/c/nitf/source/GraphicSubheader.c b/modules/c/nitf/source/GraphicSubheader.c new file mode 100644 index 000000000..fc8c637ea --- /dev/null +++ b/modules/c/nitf/source/GraphicSubheader.c @@ -0,0 +1,183 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; + * if not, see . + * + */ + +#include "nitf/GraphicSubheader.h" + +#define _NITF_CONSTRUCT_FIELD(OWNER, ID, TYPE) \ + OWNER->ID = nitf_Field_construct(ID##_SZ, TYPE, error); \ + if (!OWNER->ID) goto CATCH_ERROR; + +#define _NITF_CLONE_FIELD(DEST, SOURCE, ID) \ + DEST->ID = nitf_Field_clone(SOURCE->ID, error); \ + if (!DEST->ID) goto CATCH_ERROR; + +#define _NITF_DESTRUCT_FIELD(OWNER, ID) \ + if (OWNER->ID) nitf_Field_destruct(OWNER->ID); + +NITFAPI(nitf_GraphicSubheader *) +nitf_GraphicSubheader_construct(nitf_Error * error) +{ + /* Start by allocating the header */ + nitf_GraphicSubheader *subhdr = (nitf_GraphicSubheader *) + NITF_MALLOC(sizeof(nitf_GraphicSubheader)); + + /* Return now if we have a problem above */ + if (!subhdr) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + goto CATCH_ERROR; + } + + subhdr->extendedSection = NULL; + subhdr->securityGroup = NULL; + + subhdr->securityGroup = nitf_FileSecurity_construct(error); + if (!subhdr->securityGroup) + goto CATCH_ERROR; + + _NITF_CONSTRUCT_FIELD(subhdr, NITF_SY, NITF_BCS_A); + _NITF_CONSTRUCT_FIELD(subhdr, NITF_SID, NITF_BCS_A); + _NITF_CONSTRUCT_FIELD(subhdr, NITF_SNAME, NITF_BCS_A); + _NITF_CONSTRUCT_FIELD(subhdr, NITF_SSCLAS, NITF_BCS_A); + _NITF_CONSTRUCT_FIELD(subhdr, NITF_ENCRYP, NITF_BCS_A); + _NITF_CONSTRUCT_FIELD(subhdr, NITF_SFMT, NITF_BCS_A); + _NITF_CONSTRUCT_FIELD(subhdr, NITF_SSTRUCT, NITF_BCS_N); + _NITF_CONSTRUCT_FIELD(subhdr, NITF_SDLVL, NITF_BCS_N); + _NITF_CONSTRUCT_FIELD(subhdr, NITF_SALVL, NITF_BCS_N); + _NITF_CONSTRUCT_FIELD(subhdr, NITF_SLOC, NITF_BCS_N); + _NITF_CONSTRUCT_FIELD(subhdr, NITF_SBND1, NITF_BCS_N); + _NITF_CONSTRUCT_FIELD(subhdr, NITF_SCOLOR, NITF_BCS_A); + _NITF_CONSTRUCT_FIELD(subhdr, NITF_SBND2, NITF_BCS_N); + _NITF_CONSTRUCT_FIELD(subhdr, NITF_SRES2, NITF_BCS_N); + _NITF_CONSTRUCT_FIELD(subhdr, NITF_SXSHDL, NITF_BCS_N); + _NITF_CONSTRUCT_FIELD(subhdr, NITF_SXSOFL, NITF_BCS_N); + + subhdr->extendedSection = nitf_Extensions_construct(error); + if (!subhdr->extendedSection) + goto CATCH_ERROR; + + return subhdr; + +CATCH_ERROR: + if (subhdr) + nitf_GraphicSubheader_destruct(&subhdr); + return NULL; +} + + +NITFAPI(nitf_GraphicSubheader *) +nitf_GraphicSubheader_clone(nitf_GraphicSubheader * source, + nitf_Error * error) +{ + nitf_GraphicSubheader *subhdr = NULL; + if (source) + { + subhdr = + (nitf_GraphicSubheader *) + NITF_MALLOC(sizeof(nitf_GraphicSubheader)); + if (!subhdr) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + return NULL; + } + + subhdr->securityGroup = + nitf_FileSecurity_clone(source->securityGroup, error); + + /* Copy some fields */ + _NITF_CLONE_FIELD(subhdr, source, NITF_SY); + _NITF_CLONE_FIELD(subhdr, source, NITF_SID); + _NITF_CLONE_FIELD(subhdr, source, NITF_SNAME); + _NITF_CLONE_FIELD(subhdr, source, NITF_SSCLAS); + _NITF_CLONE_FIELD(subhdr, source, NITF_ENCRYP); + _NITF_CLONE_FIELD(subhdr, source, NITF_SFMT); + _NITF_CLONE_FIELD(subhdr, source, NITF_SSTRUCT); + _NITF_CLONE_FIELD(subhdr, source, NITF_SDLVL); + _NITF_CLONE_FIELD(subhdr, source, NITF_SALVL); + _NITF_CLONE_FIELD(subhdr, source, NITF_SLOC); + _NITF_CLONE_FIELD(subhdr, source, NITF_SBND1); + _NITF_CLONE_FIELD(subhdr, source, NITF_SCOLOR); + _NITF_CLONE_FIELD(subhdr, source, NITF_SBND2); + _NITF_CLONE_FIELD(subhdr, source, NITF_SRES2); + _NITF_CLONE_FIELD(subhdr, source, NITF_SXSHDL); + _NITF_CLONE_FIELD(subhdr, source, NITF_SXSOFL); + + /* init to NULL for safety */ + subhdr->extendedSection = NULL; + + if (source->extendedSection) + { + subhdr->extendedSection = + nitf_Extensions_clone(source->extendedSection, error); + + if (!subhdr->extendedSection) + goto CATCH_ERROR; + } + + return subhdr; + } + +CATCH_ERROR: + nitf_GraphicSubheader_destruct(&subhdr); + return NULL; +} + + +NITFAPI(void) nitf_GraphicSubheader_destruct(nitf_GraphicSubheader ** + subhdr) +{ + if (!*subhdr) + return; + + if ((*subhdr)->extendedSection) + { + nitf_Extensions_destruct(&(*subhdr)->extendedSection); + } + if ((*subhdr)->securityGroup) + { + nitf_FileSecurity_destruct(&(*subhdr)->securityGroup); + NITF_FREE((*subhdr)->securityGroup); + (*subhdr)->securityGroup = NULL; + } + + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_SY); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_SID); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_SNAME); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_SSCLAS); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_ENCRYP); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_SFMT); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_SSTRUCT); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_SDLVL); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_SALVL); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_SLOC); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_SBND1); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_SCOLOR); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_SBND2); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_SRES2); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_SXSHDL); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_SXSOFL); + + NITF_FREE(*subhdr); + *subhdr = NULL; +} diff --git a/modules/c/nitf/source/ImageIO.c b/modules/c/nitf/source/ImageIO.c new file mode 100644 index 000000000..be4b4c035 --- /dev/null +++ b/modules/c/nitf/source/ImageIO.c @@ -0,0 +1,9806 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/ImageIO.h" + + +/*! + \file + \brief NITF Image segment image data I/O object private data + (_nitf_ImageIO) + + The _nitf_ImageIO object contains the actual data that defines the object. + The opaque pointer (nitf_ImageIO) returned by the constructor points to + an instance of this structure. + + \b Notes on the constants: + +The compression, blocking mode and pixel type constants are implemented +as mutualy exclusive bit masks.\n + +Although the big-valued ("B") pixel type is included in the constant +set (for completeness), this pixel type will be treated as a type of +compression of a one byte unsigned image.\n + +*/ + +#define TRY_GET_UINT32(VALUE, DATA_PTR ) \ + if (!nitf_Field_get(VALUE, DATA_PTR, NITF_CONV_INT, NITF_INT32_SZ, error)) \ + goto CATCH_ERROR + +#define TRY_GET_UINT64(VALUE, DATA_PTR) \ + if (!nitf_Field_get(VALUE, \ + DATA_PTR, \ + NITF_CONV_INT, \ + NITF_INT64_SZ, error)) goto CATCH_ERROR + +/*! \def NITF_IMAGE_IO_COMPRESSION_NC - No compression, no blocking */ +#define NITF_IMAGE_IO_COMPRESSION_NC ((nitf_Uint32) 0x00000001) + +/*! \def NITF_IMAGE_IO_COMPRESSION_NM - No compression, blocking */ +#define NITF_IMAGE_IO_COMPRESSION_NM ((nitf_Uint32) 0x00000002) + +/*! \def NITF_IMAGE_IO_COMPRESSION_C1 - Bi-level compression, no blocking */ +#define NITF_IMAGE_IO_COMPRESSION_C1 ((nitf_Uint32) 0x00000004) + +/*! \def NITF_IMAGE_IO_COMPRESSION_C3 - JPEG compression, no blocking */ +#define NITF_IMAGE_IO_COMPRESSION_C3 ((nitf_Uint32) 0x00000008) + +/*! \def NITF_IMAGE_IO_COMPRESSION_C4- Vector quantization compression, + no blocking */ +#define NITF_IMAGE_IO_COMPRESSION_C4 ((nitf_Uint32) 0x00000010) + +/*! \def NITF_IMAGE_IO_COMPRESSION_C5 - Lossless JPEG compression, + no blocking */ +#define NITF_IMAGE_IO_COMPRESSION_C5 ((nitf_Uint32) 0x00000020) + +/*! \def NITF_IMAGE_IO_COMPRESSION_C6 - Reserved, no blocking */ +#define NITF_IMAGE_IO_COMPRESSION_C6 ((nitf_Uint32) 0x00000040) + +/*! \def NITF_IMAGE_IO_COMPRESSION_C7 - Reserved, Complex SAR compression */ +#define NITF_IMAGE_IO_COMPRESSION_C7 ((nitf_Uint32) 0x00000060) + +/*! \def NITF_IMAGE_IO_COMPRESSION_C8 - JPEG 2000 */ +#define NITF_IMAGE_IO_COMPRESSION_C8 ((nitf_Uint32) 0x00000080) + +/*! \def NITF_IMAGE_IO_COMPRESSION_I1 - Downsampled JPEG, no blocking */ +#define NITF_IMAGE_IO_COMPRESSION_I1 ((nitf_Uint32) 0x00000100) + +/*! \def NITF_IMAGE_IO_COMPRESSION_M1 - Bi-level compression, blocking */ +#define NITF_IMAGE_IO_COMPRESSION_M1 ((nitf_Uint32) 0x00000200) + +/*! \def NITF_IMAGE_IO_COMPRESSION_M3 - JPEG compression, blocking */ +#define NITF_IMAGE_IO_COMPRESSION_M3 ((nitf_Uint32) 0x00000400) + +/*! \def NITF_IMAGE_IO_COMPRESSION_M4 - Vector quantization compression, + blocking */ +#define NITF_IMAGE_IO_COMPRESSION_M4 ((nitf_Uint32) 0x00000800) + +/*! \def NITF_IMAGE_IO_COMPRESSION_M5 - Lossless JPEG compression, blocking */ +#define NITF_IMAGE_IO_COMPRESSION_M5 ((nitf_Uint32) 0x00001000) + +/*! \def NITF_IMAGE_IO_COMPRESSION_M8 - JPEG 2000 */ +#define NITF_IMAGE_IO_COMPRESSION_M8 ((nitf_Uint32) 0x00004000) + +/*! \def NITF_IMAGE_IO_BLOCKING_MODE_B - Band interleaved by block */ +#define NITF_IMAGE_IO_BLOCKING_MODE_B ((nitf_Uint32) 0x00008000) + +/*! \def NITF_IMAGE_IO_BLOCKING_MODE_P - Band interleaved by pixel */ +#define NITF_IMAGE_IO_BLOCKING_MODE_P ((nitf_Uint32) 0x00010000) + +/*! \def NITF_IMAGE_IO_BLOCKING_MODE_R - Band interleaved by row */ +#define NITF_IMAGE_IO_BLOCKING_MODE_R ((nitf_Uint32) 0x00020000) + +/*! \def NITF_IMAGE_IO_BLOCKING_MODE_S - Band sequential */ +#define NITF_IMAGE_IO_BLOCKING_MODE_S ((nitf_Uint32) 0x00040000) + +/*! \def NITF_IMAGE_IO_BLOCKING_MODE_RGB24 - Special case RGB 24-bit BIP */ +#define NITF_IMAGE_IO_BLOCKING_MODE_RGB24 ((nitf_Uint32) 0x00050000) + +/*! \def NITF_IMAGE_IO_BLOCKING_MODE_IQ - Special case IQ 2-band BIP */ +#define NITF_IMAGE_IO_BLOCKING_MODE_IQ ((nitf_Uint32) 0x00060000) + +/*! \def NITF_IMAGE_IO_NO_COMPRESSION - No compression combined mask */ +#define NITF_IMAGE_IO_NO_COMPRESSION \ + (NITF_IMAGE_IO_COMPRESSION_NC | NITF_IMAGE_IO_COMPRESSION_NM) + +/*! \def NITF_IMAGE_IO_MASK_HEADER_LEN - Length of fixed part of mask header + in the file (Does not include pad pixel value length) */ +#define NITF_IMAGE_IO_MASK_HEADER_LEN (10) + +/*! \def NITF_IMAGE_IO_NO_BLOCK - Code used for block number when there is + no block in the corresponding block cache buffer */ +#define NITF_IMAGE_IO_NO_BLOCK ((nitf_Uint32) 0xffffffff) + +/*! \def NITF_IMAGE_IO_PAD_MAX_LENGTH - Maximum lenght of a pad pixel + in bytes */ +#define NITF_IMAGE_IO_PAD_MAX_LENGTH (16) + +/*! + \def NITF_IMAGE_IO_PAD_SCANNER - Macro to a create pad scan function + + Most of the logic is to avoid the fill pixels which are at the ends of the + rows and last rows in blocks on the right and bottom border of the image. + + Notes: + + The padColumnCount is a byte count not a pixel count + The padRowCount is a row count + The padRowCount only applies if the block is the last + block in the block column + + The pad value and data have already been byte swapped if needed, + */ + +#define NITF_IMAGE_IO_PAD_SCANNER(name,type) \ + NITFPRIV(void) name \ + (struct _nitf_ImageIOBlock_s *blockIO, \ + NITF_BOOL *padFound,NITF_BOOL *dataFound) \ + { \ + type *pixels = (type *) (blockIO->blockControl.block); \ + type padValue = *((type *) (blockIO->cntl->nitf->pixel.pad)); \ + nitf_Uint32 row; \ + nitf_Uint32 col; \ + nitf_Uint32 rowEndIncr; \ + nitf_Uint32 colLimit; \ + nitf_Uint32 rowLimit; \ + _nitf_ImageIO *nitf = blockIO->cntl->nitf; \ + NITF_BOOL pFound = 0; \ + NITF_BOOL dFound = 0; \ + rowEndIncr = blockIO->padColumnCount/(nitf->pixel.bytes); \ + colLimit = blockIO->cntl->nitf->numColumnsPerBlock - rowEndIncr; \ + rowLimit = blockIO->cntl->nitf->numRowsPerBlock;\ + if(blockIO->currentRow >= (nitf->numRows - 1)) \ + rowLimit -= blockIO->padRowCount; \ + for(row=0;rowbklIO[column][band] + + The userBase field is an array of pointers, one for each requested +band. The user is likely to want to put the bands in non-continuous buffers. + +The padded field is a flags that indicates that pad pixels are +included. It is used by read operations. + +The blockIO field is a two dimensional array of _nitf_ImageIOBlock +The ioCount field gives the total number of actual I/O operations. +This field be used by an implementation of the file I/O operations to +do deferred I/O. This would allow seek optimization. The count will include +pad pixel operations. The ioCountDown field is initialized to the same +value as ioCount an can be used by the I/O function to keep track of how +many I/Os have been done. + +The downSampling, downSampleIn, and downSampleOut fields support +down-sampling. The first field is a flag indicating that the read includes +down-sampling. The other two are arrays of pointers to the input and output +buffers for the down-sample function. These arrays contain one pointer for +each band. + +See ithe documentation of _nitf_ImageIOBlock for information on down-sampling +and "FR" and "DR" fields. +*/ + +typedef struct _nitf_ImageIOControl_s +{ + /*! Parent nitfImageIO object */ + _nitf_ImageIO *nitf; + + /*! Number of row in the sub-window */ + nitf_Uint32 numRows; + + /*! Start row in the main image */ + nitf_Uint32 row; + + /*! Row skip factor */ + nitf_Uint32 rowSkip; + + /*! Number of columns in the sub-window */ + nitf_Uint32 numColumns; + + /*! Start column in the main image */ + nitf_Uint32 column; + + /*! Column skip factor */ + nitf_Uint32 columnSkip; + + /*! Array of bands to read/write */ + nitf_Uint32 *bandSubset; + + /*! Number of bands to read/write */ + nitf_Uint32 numBandSubset; + + /*! Base user buffer, one pointer per band */ + nitf_Uint8 **userBase; + + /*! Operation is read if TRUE */ + int reading; + + /*! Operation if down-sample if TRUE */ + int downSampling; + + /*! Array of input pointers for down-sample */ + NITF_DATA **downSampleIn; + + /*! Array of output pointers for down-sample */ + NITF_DATA **downSampleOut; + + /*! Number of _nitf_ImageIOBlock structures */ + nitf_Uint32 nBlockIO; + + /*! Array of _nitf_ImageIOBlock structures */ + struct _nitf_ImageIOBlock_s **blockIO; + + /*! Block number next row increment */ + nitf_Uint32 numberInc; + + /*! Data's offset in block next row byte increment */ + nitf_Uint64 blockOffsetInc; + + /*! Read/write buffer next row byte increment */ + nitf_Uint32 bufferInc; + + /*! Unpacked data buffer next row byte increment */ + nitf_Uint32 unpackedInc; + + /*! User data buffer next row byte increment */ + nitf_Uint32 userInc; + + /*! Pad pixel buffer */ + nitf_Uint8 *padBuffer; + + /*! Pad pixel buffer size in bytes */ + nitf_Uint32 padBufferSize; + + /*! Operation involved pad pixels */ + int padded; + + /*! Total I/O count */ + size_t ioCount; + + /*! I/O done count down */ + size_t ioCountDown; + + /*! Save buffer for partial down-sample windows */ + nitf_Uint8 *columnSave; +} +_nitf_ImageIOControl; + +/*! + \brief _nitf_ImageIOBlock - Block I/O structure + + The block IO structure handles one segment of one band of the current row. + After all row sements have been read/written the offsets are updated for + the next row. + + The user data buffer is part of the buffer supplied by the user. In + some blocking methods, the data can be read/written directly to/from the + user buffer and the user and buffer pointers will be the same. This is + not the case in the band interleaved by pixel blocking mode. Also the +user and write buffers must be different any time the data must be +formatted (i.e., byte swapped). + +The unpacked buffer provides an additional level of buffering when the +user requets down-sampling. Data is read full-resolution into the read +read buffer and than unpacked into the unpacked buffer. After a complete +sample window of rows have been read and unpacked, the data is down-sampled +into the user buffer. Unformatting is done in-place in the unpacked buffer. +The unpacked buffer will contain one sample window more columns than the +full resolution pixel read count. This extra space is used to hold a +sample window that is split between block columns. + +The actual current location in the user, unpacked and read/write buffers is +defined by the buffer pointers and offsets: + +user + userOffset - Current user buffer pointer +unpacked + unpackedOffset - Current unpacked buffer pointer +buffer + bufferOffset - Current readWrite buffer pointer + +The offset is updated, not the pointer. + +At the end of the read the input buffer offset points to the begining of +the read data. This offset may be adjusted by the read function on a read +by read basis. In the simplier cases, is is initialize to point to the +user buffer and incremented by nitf_ImageIO_nextRow. + +A blockMask pointer is maintained in the IO structure to handle block +sequential which has seperate masks for each band. + +The actual file offset for any read/write is: + +pixelBase + imageDataOffset + blockOffset.mark + +The blockOffset.mark is updated each row, the imageDataOffset is updated at +the end of the current block; + +The rowsUntil count is decremented after the block operations and so is set +to one less than the number of rows in the current block. For example, if +the number of blocks to be processed in the block is 1 the rowsUntil counter +is set to 0. After the first row of blocks, the counter is set to one less +than the number of rows in a block. This works because this is always right +for all rows of blocks except the first and last and in the last it is OK to +put in a to big value since there is a separate counter keeping track of the +rows processed. + +The userEqBuffer flag indicates that the user buffer is the read/write +buffer. This is useful for some read/write modes where the address of the +user buffer is not known at construct time. For example, sequential write +were the construction of the control object is done in a separate call from +the write row operations. In this case the user and buffer fields are +initialized zero and updated at each call. The flag tells the writer whether +the buffer field has to be modified. The flag would be set in the band +interleaved by row blocking mode but not in band interleaved by pixel. + +The pad counts are used to indicate that pad pixels are required at the +end of the line or pad rows at the end of the image. This type of padding +occurs when the image size in the row or column dimension is not an +interger multiple of the corresponding block dimension. The pad column +count is the number of pad bytes that must be added to the end of the row. +the count is bytes not pixels. This field is only non-zero in blocks that +are in the last block column. The writeer uses this value as a flag +indicating the need to write pad pixels. The pad row count gives the number +of pad rows that need to be added to the end of the image. sice each block +I/O object represents a column of blocks for one band, all blocks have the +same row count. The current row argument gives the current row in the image +(not the row in the sub-image). This field is required to support pad row +writes. The write loop write function (vtbl write function). Pad rows are +written when the current row is the last row in the image. This field is +not used by the reader + +The pixel count is the number of pixels associated with the block operation +The format count is the number of pixels to be formatted before write. In +the "P" blocking mode, formatting is done at the time of the write and this +is only done once per block column. The write on the last band. The entire +write for all bands is done at this time and the formatting is also deferred +till then. Therefore the format count must be the pixelCountFR times the +number of bands, hence the separate variable. + +Image down-sampling causes the user and internal read buffers and blocks to +have different resolutions, full resolution (internal buffers) and down- +sampled resolution (user buffers). Some variables and offsets are in full +resolution "units" and some in down-sampled "units". Variables and fields +ending in "FR" are full resolution and those ending in "DR" are down- +sample resolution. When not down-sampling or when writing, FR == DR. + +The sample start fields give the offset in bytes to the first column of +the first complete sample window in a row of sample windows. Data on the +current row before this offset belongs to the partial window of the last +sample window of the corresponding block in the previous block column. This +value is used to line-up the read in the buffer so that data saved from the +previous block column can be used to complete the first sample window. + +sampleStartColumn is zero based. So if "residual" is the number of sample +window columns for the last partial sample window in the previous block +column, then: residual + sampleStartColumn == columnSkip. The residual +columns and the first sampleStartColumn columns form the sample window that +is used to form the first pixel that goes in the user buffer for the current +block. If sampleStartColumn is 0, then there was a complete sample window at +the end of the previous block column and no partial neighborhood assembly +is required. + +myResidual is the residual amount from the current block column read that +will be left for the next read. If blockA and blockB are in consecutive +block columns (blockA first) the blockA->residual == blockB->myResidual +*/ + +typedef struct _nitf_ImageIOBlock_s +{ + + /*! Associated nitf_ImageIOControl object */ + _nitf_ImageIOControl *cntl; + + /*! Band associated with this I/O */ + nitf_Uint32 band; + + /*! Do the read/write if TRUE */ + int doIO; + + /*! Block number */ + nitf_Uint32 number; + + /*! Rows until next block */ + nitf_Uint32 rowsUntil; + + /*! Block mask to use */ + nitf_Uint64 *blockMask; + + /*! Pad pixel mask to use */ + nitf_Uint64 *padMask; + + /*! Block's offset from image base */ + nitf_Uint64 imageDataOffset; + + /*! Current and base offset into the block */ + _nitf_Offsets64 blockOffset; + + /*! Read/Write data buffer plus offsets */ + _nitf_DataBuffer64 rwBuffer; + + /*! Unpacked data buffer plus offsets */ + _nitf_DataBuffer32 unpacked; + + /*! Free unpacked data buffer if TRUE */ + nitf_Uint32 unpackedNoFree; + + /*! User buffer plus offsets */ + _nitf_DataBuffer32 user; + + /*! Read/write buffer is user buffer if TRUE */ + nitf_Uint32 userEqBuffer; + + /*! Read count in bytes */ + size_t readCount; + + /*! Pixel count for this operation, FR */ + size_t pixelCountFR; + + /*! Pixel count for this operation, DR */ + size_t pixelCountDR; + + /*! Format count for this operation */ + size_t formatCount; + + /*! Byte count of pad pixel columns to write */ + nitf_Uint32 padColumnCount; + + /*! Row count of pad pixel rows to write */ + nitf_Uint32 padRowCount; + + /*! Start column of the first sample window */ + nitf_Uint32 sampleStartColumn; + + /*! Partial sample columns previous block */ + nitf_Uint32 residual; + + /*! Partial sample columns current block */ + nitf_Uint32 myResidual; + + /*! Current row in the image */ + nitf_Uint32 currentRow; + + /*! Block control for cached write */ + _nitf_ImageIOBlockCacheControl blockControl; +} +_nitf_ImageIOBlock; + +/*! + \brief _nitf_ImageIOWriteControl - Write control structure + + _nitf_ImageIOWriteControl is the object used to control the writing + of image data for an ImageIO object. The object does not have a public + constructor but rather is created by one of a set of setup function. + Each of these functions configures the write control object for a + particular writing method, such as sequential writes. + + The ImageIO structure maintains a pointer to the current write control. + There can be only one active reader or writer for each ImageIO. + +This is an internal object and is not used directly by the user. + +*/ + +typedef struct _nitf_ImageIOWriteControl_s +{ + /*!< Writing method code */ + _nitf_ImageIO_writeMethod method; + _nitf_ImageIOControl *cntl; /*!< Associated control structure */ + nitf_Uint32 nextRow; /*!< Next row to write (sequential) */ +} +_nitf_ImageIOWriteControl; + +/*! + \brief _nitf_ImageIOReadControl - Read control structure + + _nitf_ImageIOReadControl is the object used to control the reading + of image data for an ImageIO object. The object does not have a public + constructor but rather is created by one of a set of setup function. + Each of these functions configures the read control object for a + particular writing method, such as sequential reads. + + The ImageIO structure maintains a pointer to the current read control. + There can be only one active reader or writer for each ImageIO. + +This is an internal object and is not used directly by the user. + +*/ + +typedef struct _nitf_ImageIOReadControl_s +{ + /*! Associated control structure */ + _nitf_ImageIOControl *cntl; +} +_nitf_ImageIOReadControl; + +/*! + \brief nitf_ImageIO_BPixelControl - The actual implementation beneath the + opaque decompression control pointer + */ + +typedef struct _nitf_ImageIO_BPixelControl +{ + + /*! Saved open argument */ + nitf_IOInterface* io; + + /*! Saved open argument */ + nitf_Uint64 offset; + + /*! Saved open argument */ + nitf_BlockingInfo *blockInfo; + + /*! Saved open argument */ + nitf_Uint64 *blockMask; + + /*! Size of compressed block in bytes */ + size_t blockSizeCompressed; + + /*! Buffer for compressed block */ + nitf_Uint8 *buffer; +} +nitf_ImageIO_BPixelControl; + +/*! + \brief nitf_ImageIO_12PixelControl - The actual implementation beneath the + opaque decompression control pointer + */ + +typedef struct _nitf_ImageIO_12PixelControl +{ + + /*! Saved open argument */ + nitf_IOInterface* io; + + /*! Saved open argument */ + nitf_Uint64 offset; + + /*! Saved open argument */ + nitf_BlockingInfo *blockInfo; + + /*! Saved open argument */ + nitf_Uint64 *blockMask; + + /*! Odd number of pixels in block flag 0 or 1, one means odd */ + nitf_Uint32 odd; + + /*! Number of pixels in block */ + size_t blockPixelCount; + + /*! Size of compressed block in bytes */ + size_t blockSizeCompressed; + + /*! Buffer for compressed block */ + nitf_Uint8 *buffer; +} +nitf_ImageIO_12PixelControl; + +/*! + \brief nitf_ImageIO_12PixelComControl - The actual implementation beneath the + opaque compression control pointer + */ + +typedef struct _nitf_ImageIO_12PixelComControl +{ + + /*! Saved open argument */ + nitf_IOInterface* io; + + /*! Saved start argument */ + nitf_Uint64 offset; + + /*! Saved start argument */ + nitf_Uint64 dataLength; + + /*! Saved start argument */ + nitf_Uint64 *blockMask; + + /*! Saved start argument */ + nitf_Uint64 *padMask; + + /*! Odd number of pixels in block flag 0 or 1, one means odd */ + nitf_Uint32 odd; + + /*! Number of pixels in block */ + size_t blockPixelCount; + + /*! Size of uncompressed block in bytes */ + size_t blockSizeUncompressed; + + /*! Size of compressed block in bytes */ + size_t blockSizeCompressed; + + /*! Amount of data written so far */ + nitf_Uint64 written; + + /*! Buffer for compressed block */ + nitf_Uint8 *buffer; +} +nitf_ImageIO_12PixelComControl; + +/*! + \brief nitf_ImageIO_decodeCompression - Decode compression string + + nitf_ImageIO_decodeCompression is the function used to decode the + compression string. It sets the _nitf_ImageIO "compression" field. + + Note: + +This is an internal function and is not intended to be called +directly by the user. + +\return Returns FALSE on error + +On error, the supplied error object is set. Possible errors include: + +Invalid type code +*/ +NITFPRIV(int) nitf_ImageIO_decodeCompression(_nitf_ImageIO* nitf, + const nitf_ImageSubheader* subhdr, + nitf_Error* error); + +/*! + \brief nitf_ImageIO_decodeBlockingMode - Decode blocking mode string + + nitf_ImageIO_decodeBlockingMode is the function used to decode the blocking + mode string. It sets the _nitf_ImageIO field "blockingMode", and the "vtbl" + fields "setup", "reader", "writer", "done", and "unformat". + + Note: + +This is an internal function and is not intended to be called +directly by the user. + +\return Returns FALSE on error + +On error, the supplied error object is set. Possible errors include: + +Invalid type code +*/ + +NITFPRIV(int) nitf_ImageIO_decodeBlockingMode(_nitf_ImageIO* nitf, + const nitf_ImageSubheader* subhdr, + nitf_Error* error); + +/*! + * Reverts the optimization modes that were added 10/2007 by tzellman. + * This is called when: + * - the user requests to read data, but does not want it + * in the RGB24 or IQ single-band format + * - the user writes data + * \param nitfI the ImageIO structure + * \param numBands the number of bands (when reading), or 0 when writing. + */ +NITFPRIV(void) nitf_ImageIO_revertOptimizedModes(_nitf_ImageIO *nitfI, + int numBands); + + +/*! + \brief nitf_ImageIO_setIO - Set the reader and writer functions + + nitf_ImageIO_setIO sets the pack and unpack functions in the vtbl field + in the nitf argument. The functions are selected based on the options set + in the nitf_ImageIO structure. The relevant options are compression, + blocking mode and pixel type. This function must be called after the + functions that initialize the correspondin fields. + + \b Note: + +This is an internal function and is not intended to be called directly +by the user. + +\return None + +*/ + +/*!< nitf_ImageIO object */ +NITFPRIV(void) nitf_ImageIO_setIO(_nitf_ImageIO * nitf); + +/*! + \brief nitf_ImageIO_setPixelDef - Set the pixel definition + + nitf_ImageIO_setPixelDef sets the pixel definition structure in the + nitf argument. All of the fields of the _nitf_ImageIO "pixel" field + are set as well as the "vtbl" "unformat" and "format" fields + + The pad pixel value (field "pad") is not set. It is initialized by + nitf_ImageIO_initMaskHeader when the mask header (which contains the value) + is read. + + Note: This is an internal function and is not intended to be called + directly by the user. + + \return Returns NITF_FAILURE on error + + On error, the supplied error object is set. Possible errors include: + + Unsupported options + + \param nitf Image IO object + \param pixelType the pixel type + \param nBitsActual The actual number of bits per pixel + \param justify The pixel justification + \param error An error to populate on failure + +*/ + +NITFPRIV(int) nitf_ImageIO_setPixelDef(_nitf_ImageIO * nitf, + char *pixelType, + nitf_Uint32 nBits, + nitf_Uint32 nBitsActual, + char *justify, + nitf_Error * error); + +/*! + \brief nitf_ImageIO_setUnpack - Set the pack and unpack functions + + nitf_ImageIO_setUnpack sets the pack and unpack functions in the vtbl + field in the nitf argument. The functions are selected baseded on the + options set in the nitf_ImageIO structure. The relevant options are + compression, blocking mode and pixel. This function must be called after + the functions that initialize the correspondin fields. + + \b Note: + +This is an internal function and is not intended to be called directly +by the user. + +\return None + +*/ + +/*!< nitf_ImageIO object */ +NITFPRIV(void) nitf_ImageIO_setUnpack(_nitf_ImageIO * nitf); + +/*! + \brief nitf_ImageIO_allocBlockArray - Allocate the IO control structure's + block array. + + nitf_ImageIO_allocBlockArray allocates the IO control structure's block + array. The array is organized as a two dimensional array indexed by block + column and band. The allocated _nitf_ImageIOBlock structures are + initialized to zero. + + The array is accessed: + +array[column][band] + +\return A pointer to the array or NULL on error. On error, the error object +is set. + +Possible errors: + +Memory allocation error +*/ + +/*!< Number of block columns */ +/*!< Number of bands */ +NITFPRIV(_nitf_ImageIOBlock **) nitf_ImageIO_allocBlockArray( + nitf_Uint32 numColumns, + nitf_Uint32 numBands, + nitf_Error * error /*! Error object */ + ); + +/*! + \brief nitf_ImageIO_freeBlockArray - Free block array + + nitf_ImageIO_freeBlockArray frees the array allcoated by the function + nitf_ImageIO_allocBlockArray. The array pointer is passed by reference + and zeroed on return. + + \return None +*/ + +/*!< The array to free */ +NITFPRIV(void) nitf_ImageIO_freeBlockArray(_nitf_ImageIOBlock *** blockIOs); + +/*! + \brief nitf_ImageIO_setup_SBR - Do read/write setup for the "S", "B", and "R" + blocking modes + + nitf_ImageIO_setup_SBR does read/write setup for the "S" (band sequential), + "B" (band interleaved by block) and "R" (band interleaved by row) + blocking modes. It is called through the _nitf_ImageIO vtbl setup field + (setup pointer) by nitf_ImageIO_read and nitf_ImageIO_write. All of the + required information is in the "cntl" argument and its parent _nitf_ImageIO + object. Fields in "cntl" are modified. + +\b Note: + +This is an internal function and is not intended to be called +directly by the user. + +\return Returns FALSE on error + +On error, FALSE is returned and the error object is set. + +Possible errors include: + +Memory allocation error +*/ + +/*!< nitf_ImageIO I/O control object */ +/*!< Error object */ +int nitf_ImageIO_setup_SBR(_nitf_ImageIOControl * cntl, + nitf_Error * error); + +/*! + + \brief nitf_ImageIO_done_SBR - Do read/write compeltion for the "S", "B" + and "R" blocking modes + + nitf_ImageIO_done_SBR does read/write completion for the "S" (band + sequential), "B" (band interleaved by block) and "R" (band interleaved by + row) blocking modes. It is called through the _nitf_ImageIO vtbl field + (done pointer) by nitf_ImageIO_read and nitf_ImageIO_write. All of the + required information is in the "cntl" argument and its parent + _nitf_ImageIO object. Fields in "cntl" are modified. + +\b Note: This is an internal function and is not intended to be called +directly by the user. + +\return Returns FALSE on error (int) + +On error, FALSE is returned and the error object is set. + +Possible errors include: + +I/O Errors +*/ + +/*!< nitf_ImageIO I/O control object */ +/*!< Error object */ +int nitf_ImageIO_done_SBR(_nitf_ImageIOControl * cntl, nitf_Error * error); + +/*! + \brief nitf_ImageIO_setup_P - Do read/write setup for the "P" blocking mode + + nitf_ImageIO_setup_P does read/write setup for the "P" (band interleaved by + pixel) blocking mode. It is called through the _nitf_ImageIO vtbl field + (setup pointer) by nitf_ImageIO_read and nitf_ImageIO_write. All of the + required information is in the "cntl" argument and its parent + _nitf_ImageIO object. Fields in "cntl" are modified. + + \b Note: + +This is an internal function and is not intended to be called +directly by the user. + +\return Returns FALSE on error + +On error, FALSE is returned and the error object is set. + +Possible errors include: + +Memory allocation error +*/ + +/*!< nitf_ImageIO I/O control object */ +/*!< Error object */ +int nitf_ImageIO_setup_P(_nitf_ImageIOControl * cntl, nitf_Error * error); + + +/*! + + \brief nitf_ImageIO_done_P - Do read/write compeltion for the "P" blocking + mode + + nitf_ImageIO_done_P does read/write completion for the "P" (band + interleaved by pixel) blocking mode. It is called through the + _nitf_ImageIO vtbl field (done pointer) by nitf_ImageIO_read and + nitf_ImageIO_write. All of the required information is in the "cntl" + argument and its parent _nitf_ImageIO object. Fields in "cntl" are modified. + +\b Note: This is an internal function and is not intended to be called +directly by the user. + +\return Returns FALSE on error (int) + +On error, FALSE is returned and the error object is set. + +Possible errors include: + +I/O Errors +*/ + +/*!< nitf_ImageIO I/O control object */ +/*!< Error object */ +int nitf_ImageIO_done_P(_nitf_ImageIOControl * cntl, nitf_Error * error); + +/*! + \brief nitf_ImageIOControl_construct - Constructor for _nitf_ImageIOControl + object + + nitf_ImageIOControl_construct is the constructor for the _nitf_ImageIOControl + object. Although this is a "C" library, it is designed using object oriented + techniques and is implemented to facilitate use by higher level languages + such as C++. The returned object must be freed by + nitf_ImageIOControl_destruct. + + The control structure manages the I/O operations required to read/write +one or more bands from a subwindow. Once set by this function, the bands +and subwindow cannot be changed (a new object must be created). + +The subwindow should be validated by the caller + +The user pointers argument should have a pointer to an sub-window sized +buffer for each requested band. For writing, there is a creation call +(i.e., nitf_ImageIO_writeSequential) followed by a write call. In this +case the user data pointers are not required for the creation call and +the users argument will be a NULL pointer + +The band list in the nitf_SubWindow is an array of band numbers. Band numbers +are zero based and follow the physical ordering of the bands in the NITF +file. The band array list is copied so the caller version does not have to +be persistent. If all bands are requested, the list can be a NULL pointer. + +\b Note: + +This is an internal function and is not intended to be called +directly by the user. + +\return The new _nitf_ImageIOControl or NULL on error + +On, error the error object is set. + +Possible errors include: + +Unimplemented +Memory allocation error +*/ + +/*!< nitf_ImageIO object */ +/*!< IO handle for read */ +NITFPRIV(_nitf_ImageIOControl *) nitf_ImageIOControl_construct(_nitf_ImageIO * nitf, nitf_IOInterface* io, nitf_Uint8 ** user, /*!< User data buffer pointers */ + nitf_SubWindow * subWindow, /*!< Sub-window to process */ + int reading, /*!< Reading if TRUE, else writing */ + nitf_Error * error /*!< Error object */ + ); + +/*! + \brief nitf_ImageIOControl_destruct - Destructor for the _nitf_ImageIOControl + object + + nitf_ImageIOControl_destruct is the destructor for the _nitf_ImageIOControl + object. Althouh this is a "C" library, it is designed using object + oriented techniques and is implemented to facilitate use by higher level + lanuages such as C++. + + This function deallocates the memory associated width the "cntl" argument + and so this handle is not valid after this call. + +The blocking specific "done" function should be called before the control +object is deleted + +The argument is set to NULL on return + +\b Note: + +This is an internal function and is not intended to be called +directly by the user. + +\return None + +*/ + +/*!< Pointer to nitf_ImageIO I/O control object */ +NITFPRIV(void) nitf_ImageIOControl_destruct(_nitf_ImageIOControl ** cntl); + +/*! + \brief nitf_ImageIOWriteControl_construct - Allocate and initialize a write + control object + + nitf_ImageIOWriteControl_construct allocates and initializes a write control. + + The caller supplied I/O control object is the one created by the calling + write setup function. The control object will be destroyed by the function + nitf_ImageIOWriteControl_writeDone + + \return Returns FALSE on error + +On error, the supplied error object is set. Possible errors include: + +Memory allocation error +*/ + +/*!< Associated I/O control object */ +/*!< Associated IO handle */ +NITFPRIV(_nitf_ImageIOWriteControl *) nitf_ImageIOWriteControl_construct( + _nitf_ImageIOControl * cntl, + nitf_IOInterface* io, + _nitf_ImageIO_writeMethod method, /*!< Writing method that will be used */ + nitf_Error * error /*!< Error object */ + ); + +/*! + \brief nitf_ImageIOWriteControl_destruct - Destructor for the write control + object + + The argument is set to NULL on return + */ + +/*!< Pointer to write control object */ +NITFPRIV(void) nitf_ImageIOWriteControl_destruct(_nitf_ImageIOWriteControl + ** cntl); + +/*! + \brief nitf_ImageIOReadControl_construct - Consructor for the read control + object + + nitf_ImageIOReadControl_construct allocates and initializes a read control. + + The caller supplied I/O control object is the one created by the calling + read setup function. + + \return Returns FALSE on error + +On error, the supplied error object is set. Possible errors include: + +Memory allocation error +*/ + +/*!< Associated I/O control object */ +/*!< Sub-window to read */ +NITFPRIV(_nitf_ImageIOReadControl *) nitf_ImageIOReadControl_construct( + _nitf_ImageIOControl * cntl, + nitf_SubWindow * subWindow, + nitf_Error * error /*!< Error object */ + ); + +/*! + \brief nitf_ImageIOReadControl_destruct - Destructor for the read control + object + + The argument is set to NULL on return + */ + +/*!< Pointer to read control object */ +NITFPRIV(void) nitf_ImageIOReadControl_destruct(_nitf_ImageIOReadControl ** + cntl); + +/*! + \brief nitf_ImageIO_bigEndian - returns TRUE on big endian machines and + FALSE on little endian machines. + + nitf_ImageIO_bigEndian returns TRUE on big endian machines and FALSE on + little endian machines. The NITF specification states that pixel values + are stored in network byte order (bi endian) + + \bNote: + + This is an internal function and is not intended to be called +directly by the user. + +\return 1 or 0 + +*/ + +NITFPRIV(int) nitf_ImageIO_bigEndian(void); + +/*! + \brief nitf_ImageIO_checkSubWindow - Check a sub-window + + nitf_ImageIO_checkSubWindow is the internal function used to to check a + sub-window. The sub-window is checked to verify that it is completely in the + image and that the band subset includes valid bands. + + The tests are made against the actual image dimensions not the padded + dimensions that can result from image blocking. + + If the sub-window specifies down-sampling (row or column skip != 1), then +the full resolution image is checked. The last sampling window irequested +can be partially out of range. + +\b Note: + +This is an internal function and is not intended to be called +directly by the user. + +\return Returns FALSE on error (int) + +On error, the supplied error object is set. Possible errors include: + +Invalid dimension or band +*/ + +/*!< The nitf_ImageIO object used do the check */ +/*!< The sub-window to check */ +NITFPRIV(int) nitf_ImageIO_checkSubWindow(_nitf_ImageIO * nitf, + nitf_SubWindow * subWindow, + int *all, /*!< Returns TRUE if the sub-window is the entire image */ + nitf_Error * error /*!< Error object */ + ); + +/*! + \brief nitf_ImageIO_checkOneRead - Check for single read case + + nitf_ImageIO_checkOneRead determines if the uer request can be satisfied + in a single read operation. This will happen in three cases: + + If A: + + The image has only one block + The full image is being read + The blocking mode is "B" +No compression (for now) + +Or B: + +The image has only one block per column +The full image is being read +The blocking mode is "S" +No compression (for now) + +Or C: +The image has only one band +The image has only one block per column +The full image is being read +The blocking mode is "B" +No compression (for now) + +\return TRUE is returned if the request can be done in one read + +*/ + +/*!< The NITF object internal data */ +/*!< Entire image is being read if TRUE */ +NITFPRIV(NITF_BOOL) nitf_ImageIO_checkOneRead(_nitf_ImageIO * nitfI, + NITF_BOOL all); + +/*! + \brief nitf_ImageIO_mkMasks - Make the block and pad pixel masks + + nitf_ImageIO_mkMasks makes the block and pad pixel masks. It also sets + up the pad pixel value. If reading, the masks are read from the file if + they are present. Otherwise, a linear mask (no pad blocks) is created for + the block mask and an empty pad mask (all blocks marked pad free). A pad + pixel value if present, overrides one specified by the user + + The pixelBase offset in the parent nitf_ImageIO structure is adjusted based + on the mask data (if any) + +The "reading" argument indicates that the call is part of a read operation. +If TRUE the function will read any available mask information from the file. + +\b Note: + +This is an internal function and is not intended to be called +directly by the user. + +\return FALSE is returned on error + +On error, the error object object is set. Possible errors include: + +Memory allocation error +I/O Error +*/ + +/*!< The ImageIO object */ +/*!< IO handle for reads */ +NITFPRIV(int) nitf_ImageIO_mkMasks(nitf_ImageIO * img, nitf_IOInterface* io, int reading, /*!< Read operation if TRUE */ + nitf_Error * error /*!< Used for error handling */ + ); + +/*! + \brief nitf_ImageIO_initMaskHeader - Initialize the mask header structure + in the _nitf_ImageIO structure. + + nitf_ImageIO_initMaskHeader initializes the mask header structure in the + _nitf_ImageIO structure. It may read the information from the file or + construct a default one. + + The "reading" argument indicates that the call is part of a read operation. + If TRUE the function will read any available mask information from the file. + +\b Note: + +This is an internal function and is not intended to be called +directly by the user. + +\return FALSE is returned on error + +On error, the error object is set. Possible errors include: + +I/O Error +*/ + +/*!< The ImageIO object */ +/*!< IO handle for reads */ +NITFPRIV(int) nitf_ImageIO_initMaskHeader(_nitf_ImageIO * nitf, nitf_IOInterface *io, nitf_Uint32 blockCount, /*!< Total number of blocks in the file */ + int reading, /*!< Read operation if TRUE */ + nitf_Error * error /*!< Used for error handling */ + ); + +/*! + \brief nitf_ImageIO_readMaskHeader - Read the mask header structure + + nitf_ImageIO_readMaskHeader reads the mask header from the file and uses + the values to initialize the mask header strcuture in the ImageIO object. + The values are byte swapped if needed. The blockMask file in the ImageIO + object is modified. + + \return FALSE is returned on error and the error object is set +*/ + +/*!< The ImageIO object */ +/*!< IO handle for reads */ +NITFPRIV(int) nitf_ImageIO_readMaskHeader(_nitf_ImageIO * nitf, nitf_IOInterface* io, nitf_Error * error /*!< Used for error handling */ + ); + +/*! + \brief nitf_ImageIO_swapMaskHeader - Byte swap the mask header + + nitf_ImageIO_swapMaskHeader byte swaps the mask header. The mask + header, which is a binary structure in the NITF file, needs to + be byte swapped in little endian machines. Swapping is required + before writing and afetr reading + + \return None +*/ + +/*numRows, &numRows, error); + NITF_TRY_GET_UINT32(sub->numCols, &numColumns, error); + NITF_TRY_GET_UINT32(sub->numImageBands, &numBands, error); + NITF_TRY_GET_UINT32(sub->numMultispectralImageBands, &xBands, error); + numBands += xBands; + pixelType = sub->pixelValueType->raw; + NITF_TRY_GET_UINT32(sub->numBitsPerPixel, &nBits, error); + NITF_TRY_GET_UINT32(sub->actualBitsPerPixel, &nBitsActual, error); + justification = sub->pixelJustification->raw; + NITF_TRY_GET_UINT32(sub->numBlocksPerRow, &nBlocksPerRow, error); + NITF_TRY_GET_UINT32(sub->numBlocksPerCol, &nBlocksPerColumn, error); + NITF_TRY_GET_UINT32(sub->numPixelsPerVertBlock, &numRowsPerBlock, error); + NITF_TRY_GET_UINT32(sub->numPixelsPerHorizBlock, &numColumnsPerBlock, + error); + + nitf = (_nitf_ImageIO *) NITF_MALLOC(sizeof(_nitf_ImageIO)); + if (nitf == NULL) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_MEMORY, + "Error allocating object: %s", NITF_STRERROR(NITF_ERRNO)); + return NULL; + } + /* Initialize all fields to zero */ + memset(nitf, 0, sizeof(_nitf_ImageIO)); + + /* Adjust block column and row counts for 2500C */ + if ((nBlocksPerColumn == 1) && (numRowsPerBlock == 0)) + numRowsPerBlock = numRows; + if ((nBlocksPerRow == 1) && (numColumnsPerBlock == 0)) + numColumnsPerBlock = numColumns; + + nitf->numRows = numRows; + nitf->numColumns = numColumns; + nitf->numBands = numBands; + nitf->nBlocksPerRow = nBlocksPerRow; + nitf->nBlocksPerColumn = nBlocksPerColumn; + nitf->numRowsPerBlock = numRowsPerBlock; + nitf->numColumnsPerBlock = numColumnsPerBlock; + nitf->numRowsActual = numRowsPerBlock * nBlocksPerColumn; + nitf->numColumnsActual = numColumnsPerBlock * nBlocksPerRow; + nitf->compressor = compressor; + nitf->decompressor = decompressor; + nitf->compressionControl = NULL; + nitf->decompressionControl = NULL; + nitf->blockControl.number = NITF_IMAGE_IO_NO_BLOCK; + nitf->blockControl.freeFlag = 1; + nitf->blockControl.block = NULL; + nitf->cachedWriteFlag = 0; + + nitf_ImageIO_setDefaultParameters(nitf); + + nitf->imageBase = offset; + nitf->pixelBase = offset; + nitf->dataLength = length; + + nitf->blockMask = NULL; /* Set by first read/write */ + + /* The order of these calls must match what's below... + * 1. decodeCompression() sets nitf->compression + * 2. Among other things, setPixelDef() sets vtbl.unformat and vtbl.format + * which handle endian swapping. However, we don't want to do endian + * swapping if we have a compressor/decompressor (because it will do + * this for us), so we need to do #1 first to we know what compression + * we've got. + * 3. For certain input types, decodeBlockingMode() will fake out the + * number of bands and then override vtbl.unformat (in order to + * optimize the read). So #2 has to occur first so it doesn't clobber + * what we do here (plus this step is counting on #2 having initialized + * vtbl.unformat). + */ + if (!nitf_ImageIO_decodeCompression(nitf, subheader, error) || + !nitf_ImageIO_setPixelDef(nitf, pixelType, nBits, nBitsActual, + justification, error) || + !nitf_ImageIO_decodeBlockingMode(nitf, subheader, error)) + { + return NULL; + } + + /* + * Check for pixel type B (binary), if there is no decompressor, set + * The psuedo decompressor for B typ3 pixels + */ + + if ((nitf->pixel.type == NITF_IMAGE_IO_PIXEL_TYPE_B) + && (nitf->compression & NITF_IMAGE_IO_NO_COMPRESSION)) + nitf->decompressor = &nitf_ImageIO_bPixelInterface; + + /* + * Check for pixel NBPP == 12 and ABPP == 12, (pixel type 12) if + * there is no decompressor, set the psuedo decompressor for the 12 + * bit pixel type. Also set the compressor in case this is a write + */ + + if ((nitf->pixel.type == NITF_IMAGE_IO_PIXEL_TYPE_12) + && (nitf->compression & NITF_IMAGE_IO_NO_COMPRESSION)) + { + nitf->decompressor = &nitf_ImageIO_12PixelInterface; + nitf->compressor = &nitf_ImageIO_12PixelComInterface; + } + + if (nitf->blockingMode == NITF_IMAGE_IO_BLOCKING_MODE_S) + { + nitf->nBlocksTotal = + nitf->nBlocksPerRow * nitf->nBlocksPerColumn * nitf->numBands; + nitf->blockSize = (size_t)numRowsPerBlock * + (size_t)numColumnsPerBlock * (nitf->pixel.bytes); + } + else + { + nitf->nBlocksTotal = nitf->nBlocksPerRow * nitf->nBlocksPerColumn; + nitf->blockSize = (size_t)numRowsPerBlock * (size_t)numColumnsPerBlock * + (nitf->pixel.bytes) * (nitf->numBands); + } + + nitf_ImageIO_setUnpack(nitf); + nitf_ImageIO_setIO(nitf); + + /* Call if compressor open function if the compressor is not NULL */ + if(nitf->compressor != NULL) + { + nitf->compressionControl = + (*(nitf->compressor->open))(sub,options,error); + if(nitf->compressionControl == NULL) + { + nitf_ImageIO_destruct((nitf_ImageIO **) &nitf); + return(NULL); + } + } + + /* Call if decompressor open function if the decompressor is not NULL */ + if(nitf->decompressor != NULL) + { + nitf->decompressionControl = + (*(nitf->decompressor->open))(sub,options,error); + if(nitf->decompressionControl == NULL) + { + nitf_ImageIO_destruct((nitf_ImageIO **) &nitf); + return(NULL); + } + } + + return (nitf_ImageIO *) nitf; + +CATCH_ERROR: + return NULL; +} + + +NITFPROT(nitf_ImageIO *) nitf_ImageIO_clone(nitf_ImageIO * image, + nitf_Error * error) +{ + _nitf_ImageIO *clone; /* The result */ + + clone = (_nitf_ImageIO *) NITF_MALLOC(sizeof(_nitf_ImageIO)); + if (clone == NULL) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_MEMORY, + "Error allocating object: %s", NITF_STRERROR(NITF_ERRNO)); + return NULL; + } + + /* Make copy */ + *clone = *((_nitf_ImageIO *) image); + + /* Clear some fields */ + + clone->blockInfoFlag = 0; + + memset(&(clone->blockControl), 0, + sizeof(_nitf_ImageIOBlockCacheControl)); + + clone->decompressionControl = NULL; + + memset(&(clone->maskHeader), 0, sizeof(_nitf_ImageIO_MaskHeader)); + clone->blockMask = NULL; + clone->padMask = NULL; + + return (nitf_ImageIO *) clone; +} + +NITFPROT(void) nitf_ImageIO_destruct(nitf_ImageIO ** nitf) +{ + _nitf_ImageIO *nitfp; /* Pointer to internal type */ + nitf_Error error; /* For decompressor free block call */ + + if (*nitf == NULL) + return; + + nitfp = *((_nitf_ImageIO **) nitf); + + if (nitfp->blockMask != NULL) + NITF_FREE(nitfp->blockMask); + + if (nitfp->padMask != NULL) + NITF_FREE(nitfp->padMask); + + if (nitfp->blockControl.block != NULL) + { + /* No plugin */ + if (nitfp->decompressor == NULL) + NITF_FREE(nitfp->blockControl.block); + else + (*(nitfp->decompressor->freeBlock)) (nitfp-> + decompressionControl, + nitfp->blockControl.block, + &error); + } + + if (nitfp->decompressionControl != NULL) + (*(nitfp->decompressor->destroyControl))(&(nitfp->decompressionControl)); + + if (nitfp->compressionControl != NULL) + (*(nitfp->compressor->destroyControl))(&(nitfp->compressionControl)); + + NITF_FREE(nitfp); + *nitf = NULL; + return; +} + +/*========================= nitf_ImageIO_read ================================*/ + +NITFPROT(NITF_BOOL) nitf_ImageIO_read(nitf_ImageIO * nitf, + nitf_IOInterface* io, + nitf_SubWindow * subWindow, + nitf_Uint8 ** user, + int *padded, nitf_Error * error) +{ + _nitf_ImageIO *nitfI; /* Internal version of nitf */ + int all; /* Full image read flag */ + nitf_BlockingInfo *blockInfo; /* For get blocking info call */ + NITF_BOOL oneRead; /* Complete request in one read flag */ + int oneBand; /* One band flag */ + _nitf_ImageIOControl *cntl; /* IO control structure */ + /* Read control structure */ + _nitf_ImageIOReadControl *readCntl; + nitf_SubWindow tmpSub; /* Temp sub-window structure for one band loop */ + nitf_Uint32 band; /* Current band */ + int ret; /* Return value */ + + ret = 1; /* To avoid warning */ + nitfI = (_nitf_ImageIO *) nitf; + + if ((nitfI->writeControl != NULL) || (nitfI->readControl != NULL)) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_MEMORY, + "I/O operation in progress"); + return NITF_FAILURE; + } + + /* *possibly* revert the optimized modes */ + nitf_ImageIO_revertOptimizedModes(nitfI, subWindow->numBands); + + /* Create I/O control */ + + /* + * Check the request, set-up blocking first since the sub-window + * check requires the block size + */ + + blockInfo = nitf_ImageIO_getBlockingInfo(nitf, io, error); + if (blockInfo == NULL) + return NITF_FAILURE; + + /* Not needed */ + nitf_BlockingInfo_destruct(&blockInfo); + + if (!nitf_ImageIO_checkSubWindow(nitfI, subWindow, &all, error)) + return 0; + + /* + * Look for single read cases (down-sampling never does a single read ori + * one band reads if the method is multi-band) + */ + + oneBand = nitfI->oneBand; + if ((subWindow->downsampler != NULL) && + ((subWindow->downsampler->rowSkip != 1) + || (subWindow->downsampler->colSkip != 1))) + { + oneRead = 0; + if (subWindow->downsampler->multiBand) + oneBand = 0; + } + else + oneRead = nitf_ImageIO_checkOneRead(nitfI, all); + + /* Set-up and do the read (one band at a time or all bands at once) */ + + if (oneBand || oneRead) + { + tmpSub = *subWindow; + for (band = 0; band < subWindow->numBands; band++) + { + tmpSub.bandList = subWindow->bandList + band; + tmpSub.numBands = 1; + cntl = nitf_ImageIOControl_construct(nitfI, + io, + user + band, + &tmpSub, 1 /* Reading */ , + error); + if (cntl == NULL) + return 0; + + readCntl = + nitf_ImageIOReadControl_construct(cntl, subWindow, error); + if (readCntl == NULL) + { + nitf_ImageIOControl_destruct(&cntl); + return 0; + } + nitfI->readControl = readCntl; + if (oneRead) + ret = nitf_ImageIO_oneRead(cntl, io, error); + else + { + if (cntl->downSampling) + ret = + nitf_ImageIO_readRequestDownSample(cntl, subWindow, + io, error); + else + ret = nitf_ImageIO_readRequest(cntl, io, error); + } + + nitf_ImageIOControl_destruct(&cntl); + nitf_ImageIOReadControl_destruct(&(nitfI->readControl)); + } + } + else + { + cntl = nitf_ImageIOControl_construct(nitfI, io, + user, + subWindow, 1 /* Reading */ , + error); + if (cntl == NULL) + return 0; + + readCntl = + nitf_ImageIOReadControl_construct(cntl, subWindow, error); + if (readCntl == NULL) + { + nitf_ImageIOControl_destruct(&cntl); + return 0; + } + nitfI->readControl = readCntl; + + if (cntl->downSampling) + ret = + nitf_ImageIO_readRequestDownSample(cntl, subWindow, io, + error); + else + ret = nitf_ImageIO_readRequest(cntl, io, error); + + *padded = cntl->padded; + nitf_ImageIOControl_destruct(&cntl); + nitf_ImageIOReadControl_destruct(&(nitfI->readControl)); + } + + return ret; +} + + +NITFPROT(NITF_BOOL) nitf_ImageIO_writeDone(nitf_ImageIO * object, + nitf_IOInterface* io, + nitf_Error * error) +{ + int ret; /* Return from flush */ + /* Internal representations */ + _nitf_ImageIO *nitfI; + _nitf_ImageIOWriteControl *cntl; + + nitfI = (_nitf_ImageIO *) object; + cntl = nitfI->writeControl; + if (cntl == NULL) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_COMPRESSION, + "Write operation in not progress"); + return NITF_FAILURE; + } + + /* Call the compression end function */ + + if(nitfI->compressor != NULL) + { + if(!(*(nitfI->compressor->end))(nitfI->compressionControl,io,error)) + { + return NITF_FAILURE; + } + } + + /* Flush the object */ + + ret = nitf_ImageIO_flush(object, io, error); + + /* Destroy the I/O control */ + + nitf_ImageIOControl_destruct(&(cntl->cntl)); + nitf_ImageIOWriteControl_destruct(& + (((_nitf_ImageIO *) object)-> + writeControl)); + + return ret; +} + + +NITFPROT(NITF_BOOL) nitf_ImageIO_flush(nitf_ImageIO * object, + nitf_IOInterface* io, + nitf_Error * error) +{ + /* Internal view of object */ + _nitf_ImageIOWriteControl *wrtCntl; + nitf_Off currentOffset; /* File offset when called (restored) */ + + wrtCntl = ((_nitf_ImageIO *) object)->writeControl; + + if (wrtCntl == NULL) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_MEMORY, + "Write operation in not progress"); + return NITF_FAILURE; + } + + currentOffset = nitf_IOInterface_tell(io, error); + + if (!nitf_ImageIO_writeMasks(wrtCntl->cntl->nitf, io, error)) + return NITF_FAILURE; + + if (!NITF_IO_SUCCESS(nitf_IOInterface_seek(io, currentOffset, NITF_SEEK_SET, error))) + return NITF_FAILURE; + + return NITF_SUCCESS; +} + + +/*========================= nitf_ImageIO_writeSequential =====================*/ + +NITFPROT(NITF_BOOL) nitf_ImageIO_writeSequential(nitf_ImageIO * nitf, + nitf_IOInterface* io, + nitf_Error * error) +{ + _nitf_ImageIO *nitfI; /* Internal version of nitf */ + nitf_SubWindow *subWindow; /* Needed for the constructor */ + _nitf_ImageIOControl *cntl; /* I/O control structure */ + /* The write control structure */ + _nitf_ImageIOWriteControl *writeCntl; + + nitfI = (_nitf_ImageIO *) nitf; + + /* *possibly* revert the optimized modes */ + nitf_ImageIO_revertOptimizedModes(nitfI, 0); + + /* Check for I/O in progress */ + + if ((nitfI->writeControl != NULL) || (nitfI->readControl != NULL)) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_MEMORY, + "I/O operation in progress"); + return NITF_FAILURE; + } + + /* Create I/O control */ + + subWindow = nitf_SubWindow_construct(error); + subWindow->startRow = 0; + subWindow->numRows = nitfI->numRows; + subWindow->startCol = 0; + subWindow->numCols = nitfI->numColumns; + subWindow->bandList = NULL; + subWindow->numBands = nitfI->numBands; + + cntl = nitf_ImageIOControl_construct(nitfI, io, NULL, + subWindow, 0 /* Writing */ , + error); + nitf_SubWindow_destruct(&subWindow); + + if (cntl == NULL) + return NITF_FAILURE; + + /* Get the result object */ + + writeCntl = nitf_ImageIOWriteControl_construct(cntl, io, + SEQUENTIAL_ALL_BANDS, + error); + if (writeCntl == NULL) + { + nitf_ImageIOControl_destruct(&cntl); + return NITF_FAILURE; + } + + nitfI->writeControl = writeCntl; + return NITF_SUCCESS; +} + + +NITFPROT(NITF_BOOL) nitf_ImageIO_writeRows(nitf_ImageIO * object, + nitf_IOInterface* io, + nitf_Uint32 numRows, + nitf_Uint8 ** data, + nitf_Error * error) +{ + _nitf_ImageIO *nitf; /* Parent _nitf_ImageIO object */ + /* Internal representation */ + _nitf_ImageIOWriteControl *cntl; + /* Associated IO control object */ + _nitf_ImageIOControl *ioCntl; + nitf_Uint32 idxIO; /* Current block IO index (linear array) */ + nitf_Uint32 nBlockCols; /* Number of block columns */ + nitf_Uint32 numBands; /* Number of bands */ + nitf_Uint32 col; /* Block column index */ + nitf_Uint32 row; /* Current row in sub-window */ + nitf_Uint32 band; /* Current band in sub-window */ + _nitf_ImageIOBlock *blockIO; /* The current block IO structure */ + + cntl = ((_nitf_ImageIO *) object)->writeControl; + if (cntl == NULL) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_MEMORY, + "Write operation in not progress"); + return NITF_FAILURE; + } + + ioCntl = cntl->cntl; + nitf = ioCntl->nitf; + numBands = ioCntl->numBandSubset; + nBlockCols = ioCntl->nBlockIO / numBands; + + /* Check for row out of bounds */ + + if (cntl->nextRow + numRows > nitf->numRows) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_MEMORY, + "Row write request of %ld rows at row %ld exceeds row limit %ld", + numRows, cntl->nextRow, nitf->numRows); + return NITF_FAILURE; + } + + /* Setup user pointers in blockIO structures */ + + blockIO = &(ioCntl->blockIO[0][0]); + for (idxIO = 0; idxIO < ioCntl->nBlockIO; idxIO++) + { + /* Current user data pointer from "data" argument */ + nitf_Uint8 *user; + + user = data[ioCntl->bandSubset[blockIO->band]]; + + /* Setup user and read/write buffers to start and reset offsets */ + + blockIO->user.buffer = user; + if (blockIO->userEqBuffer) + blockIO->rwBuffer.buffer = user; + + blockIO->user.offset.mark = blockIO->user.offset.orig; + blockIO->rwBuffer.offset.mark = blockIO->rwBuffer.offset.orig; + blockIO += 1; + } + + /* Main write loop */ + blockIO = &(ioCntl->blockIO[0][0]); + blockIO->currentRow = cntl->nextRow; + for (col = 0; col < nBlockCols; col++) + { + for (row = 0; row < numRows; row++) + { + for (band = 0; band < numBands; band++) + { + blockIO = &(ioCntl->blockIO[col][band]); + + if (nitf->vtbl.pack != NULL) + (*(nitf->vtbl.pack)) (blockIO, error); + else + memcpy(blockIO->rwBuffer.buffer,blockIO->user.buffer + + blockIO->user.offset.mark,blockIO->readCount); + + if (blockIO->doIO) + { + if (nitf->vtbl.format != NULL) + (*(nitf->vtbl.format)) (blockIO->rwBuffer.buffer + + blockIO->rwBuffer.offset.mark, + blockIO->formatCount, + nitf->pixel.shift); + + if (!(*(nitf->vtbl.writer)) (blockIO, io, error)) + return NITF_FAILURE; + } + blockIO->currentRow += 1; + + /* + * You have to check for last row and not call + * nitf_ImageIO_nextRow because if the last row is the last + * line in the last block, you can + * wind up accessing past the end of the block mask while + * setting-up for + * the non-existant next block. + */ + if (row != nitf->numRows - 1) + nitf_ImageIO_nextRow(blockIO, 0); + + if (blockIO->rowsUntil == 0) + blockIO->rowsUntil = nitf->numRowsPerBlock - 1; + else + blockIO->rowsUntil -= 1; + } + } + } + + cntl->nextRow += numRows; + return NITF_SUCCESS; +} + + +NITFPROT(NITF_BOOL) nitf_ImageIO_setPadPixel(nitf_ImageIO * object, + nitf_Uint8 * value, + nitf_Uint32 length, + nitf_Error* error) +{ + + _nitf_ImageIO* nio = (_nitf_ImageIO*)object; + + if (length > NITF_IMAGE_IO_PAD_MAX_LENGTH) + length = NITF_IMAGE_IO_PAD_MAX_LENGTH; + + memmove(nio->pixel.pad, value, length); + + /* The pad value is stored big endian */ + + switch (length) + { + case 2: + { + nitf_Uint16* int16 = + (nitf_Uint16*)&(nio->pixel.pad); + *int16 = NITF_HTONS(*int16); + break; + + } + case 4: + { + nitf_Uint32* int32 = + (nitf_Uint32*)&(nio->pixel.pad); + *int32 = NITF_HTONL(*int32); + break; + } + case 8: + { + nitf_Uint64* int64 = + (nitf_Uint64*)&(nio->pixel.pad); + + if (nio->pixel.type == NITF_IMAGE_IO_PIXEL_TYPE_C) + { + *int64 = NITF_HTONLC(*int64); + + } + else + { + *int64 = NITF_HTONLL(*int64); + } + break; + } + + /* The 16 byte complex pixel is not actually possible */ + default: + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_INVALID_PARAMETER, + "Invalid format size [%s]", length); + return NITF_FAILURE; + } + + return NITF_SUCCESS; +} + + +/*=================== nitf_ImageIO_pixelSize =================================*/ + +NITFPROT(nitf_Uint32) nitf_ImageIO_pixelSize(nitf_ImageIO * nitf) +{ + return (((_nitf_ImageIO *) nitf)->pixel.bytes); +} + + +/*=================== nitf_ImageIO_pixelSize =================================*/ + +NITFPROT(NITF_BOOL) nitf_ImageIO_setFileOffset(nitf_ImageIO * nitf, + nitf_Uint64 offset, + nitf_Error * error) +{ + _nitf_ImageIO *nitfI; /* Internal version of the handle */ + + nitfI = (_nitf_ImageIO *) nitf; + + /* Write in progress */ + if (nitfI->writeControl != NULL) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_MEMORY, + "Can not change file offset during I/O operation"); + return NITF_FAILURE; + } + + /* + * The two relevant fields are imageBase and pixelBase. pixelBase the + * imageBase offset plus another offset so subtract the current imageBase + * value from pixelBase and then add the new offset. + */ + + nitfI->pixelBase -= nitfI->imageBase; + nitfI->imageBase = offset; + nitfI->pixelBase += offset; + return NITF_SUCCESS; +} + + +NITFPROT(nitf_BlockingInfo *) nitf_BlockingInfo_construct(nitf_Error * + error) +{ + /* Allocate the info object */ + nitf_BlockingInfo *info = + (nitf_BlockingInfo *) NITF_MALLOC(sizeof(nitf_BlockingInfo)); + + /* Return now if we have a problem above */ + if (!info) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + return NULL; + } + + return info; +} + + +/*=================== nitf_BlockingInfo_destruct ===========================*/ +NITFPROT(void) nitf_BlockingInfo_destruct(nitf_BlockingInfo ** info) +{ + NITF_FREE(*info); + *info = NULL; + return; +} + + +/*=================== nitf_ImageIO_getBlockingInfo ===========================*/ + +NITFPROT(nitf_BlockingInfo *) +nitf_ImageIO_getBlockingInfo(nitf_ImageIO * image, + nitf_IOInterface* io, + nitf_Error *error) +{ + _nitf_ImageIO *img; /* Internal representation of object */ + nitf_BlockingInfo *result; /* The requested information */ + + img = (_nitf_ImageIO *) image; + + /* Create the block mask if it has not been done already */ + + if (img->blockMask == NULL) + { + if (!nitf_ImageIO_mkMasks(img, io, 1, error)) + return NULL; + } + + /* Allocate the result */ + + result = nitf_BlockingInfo_construct(error); + if (result == NULL) + { + return NULL; + } + + if (img->blockInfoFlag) + { + *result = img->blockInfo; /* Make a copy */ + return result; + } + + img->blockInfo.numBlocksPerRow = img->nBlocksPerRow; + img->blockInfo.numBlocksPerCol = img->nBlocksPerColumn; + img->blockInfo.numRowsPerBlock = img->numRowsPerBlock; + img->blockInfo.numColsPerBlock = img->numColumnsPerBlock; + img->blockInfo.length = img->blockSize; + + /* + * Initialize the decompression control object if image is compressed. + * This is done here because the decompressor may update the blocking + * information. + */ + + if(img->decompressor != NULL) + { + /* NOTE: We are counting on only getting to this point on the first + * call to this function since blockInfoFlag should get set + * below. If that convention changes, this needs to get + * reworked. + */ + if(!(*(img->decompressor->start)) ( + img->decompressionControl, io, img->pixelBase, + img->dataLength - img->maskHeader.imageDataOffset, + &(img->blockInfo), img->blockMask, error) ) + { + nitf_BlockingInfo_destruct(&result); + return NULL; + } + } + + img->blockInfoFlag = 1; /* Only do this once */ + *result = img->blockInfo; /* Make a copy */ + return result; +} + +NITFPROT(int) nitf_ImageIO_setWriteCaching(nitf_ImageIO * nitf, int enable) +{ + _nitf_ImageIO *initf; /* Internal representation of object */ + int saved; /* Saved result */ + + initf = (_nitf_ImageIO *) nitf; + saved = initf->cachedWriteFlag; + if (enable) + { + initf->vtbl.writer = nitf_ImageIO_cachedWriter; + initf->cachedWriteFlag = 1; + } + else + { + initf->vtbl.writer = nitf_ImageIO_uncachedWriter; + initf->cachedWriteFlag = 0; + } + + return saved; +} + +NITFPROT(void) nitf_ImageIO_setReadCaching(nitf_ImageIO * nitf) +{ + _nitf_ImageIO *initf; /* Internal representation of object */ + + initf = (_nitf_ImageIO *) nitf; + initf->vtbl.reader = nitf_ImageIO_cachedReader; + + return; +} + +/*=================== nitf_BlockingInfo_print ================================*/ + +NITFPROT(void) nitf_BlockingInfo_print(nitf_BlockingInfo * info, + FILE * file) +{ +#ifdef NITF_DEBUG + if (file == NULL) + file = stdout; + + fprintf(file, "nitf_ImageIOBlockingInfo structure:\n"); + fprintf(file, " Number of blocks per row: %ld\n", + info->numBlocksPerRow); + fprintf(file, " Number of blocks per column: %ld\n", + info->numBlocksPerCol); + fprintf(file, " Number of rows per block: %ld\n", + info->numRowsPerBlock); + fprintf(file, " Number of columns per block: %ld\n", + info->numColsPerBlock); + fprintf(file, " Block length in bytes: %ld\n", info->length); +#else + /* Silence compiler warnings about unused variables */ + (void)info; + (void)file; +#endif + return; +} + + +/*============================================================================*/ +/*======================== Internal Functions ================================*/ +/*============================================================================*/ + +NITFPRIV(void) nitf_ImageIO_revertOptimizedModes(_nitf_ImageIO *nitfI, int numBands) +{ + if (nitfI->blockingMode == NITF_IMAGE_IO_BLOCKING_MODE_RGB24 && + (numBands == 3 || numBands == 0)) + { + numBands = 3; + /* revert to normal 'P' mode */ + nitfI->blockingMode = NITF_IMAGE_IO_BLOCKING_MODE_P; + nitfI->vtbl.setup = nitf_ImageIO_setup_P; + nitfI->vtbl.done = nitf_ImageIO_setup_P; + nitfI->numBands = numBands; + nitfI->pixel.bytes /= numBands; + /* reset the unpack functions */ + nitf_ImageIO_setUnpack(nitfI); + } + else if (nitfI->blockingMode == NITF_IMAGE_IO_BLOCKING_MODE_IQ && + (numBands == 2 || numBands == 0)) + { + numBands = 2; + /* revert to normal 'P' mode */ + nitfI->blockingMode = NITF_IMAGE_IO_BLOCKING_MODE_P; + nitfI->vtbl.setup = nitf_ImageIO_setup_P; + nitfI->vtbl.done = nitf_ImageIO_setup_P; + nitfI->numBands = numBands; + nitfI->pixel.bytes /= numBands; + /* reset the unpack functions */ + nitf_ImageIO_setUnpack(nitfI); + if (nitfI->vtbl.unformat) + { + switch (nitfI->pixel.bytes) + { + case 8: + nitfI->vtbl.unformat = nitf_ImageIO_swapOnly_8; + break; + case 4: + nitfI->vtbl.unformat = nitf_ImageIO_swapOnly_4; + break; + case 2: + nitfI->vtbl.unformat = nitf_ImageIO_swapOnly_2; + break; + case 1: + nitfI->vtbl.unformat = NULL; + break; + default: + /* No optimized mode */ + return; + } + } + } +} + + +/*======================== nitf_ImageIO_decodeCompression ====================*/ +NITFPRIV(int) nitf_ImageIO_decodeCompression(_nitf_ImageIO* nitf, + const nitf_ImageSubheader* subhdr, + nitf_Error* error) +{ + const char* const compression = subhdr->imageCompression->raw; + + if (strncmp(compression, "NC", 2) == 0) + { + nitf->compression = NITF_IMAGE_IO_COMPRESSION_NC; + } + else if (strncmp(compression, "NM", 2) == 0) + { + nitf->compression = NITF_IMAGE_IO_COMPRESSION_NM; + } + else if (strncmp(compression, "C1", 2) == 0) + { + nitf->compression = NITF_IMAGE_IO_COMPRESSION_C1; + } + else if (strncmp(compression, "C3", 2) == 0) + { + nitf->compression = NITF_IMAGE_IO_COMPRESSION_C3; + } + else if (strncmp(compression, "C4", 2) == 0) + { + nitf->compression = NITF_IMAGE_IO_COMPRESSION_C4; + } + else if (strncmp(compression, "C5", 2) == 0) + { + nitf->compression = NITF_IMAGE_IO_COMPRESSION_C5; + } + else if (strncmp(compression, "C6", 2) == 0) + { + nitf->compression = NITF_IMAGE_IO_COMPRESSION_C6; + } + else if (strncmp(compression, "C7", 2) == 0) + { + nitf->compression = NITF_IMAGE_IO_COMPRESSION_C7; + } + else if (strncmp(compression, "C8", 2) == 0) + { + nitf->compression = NITF_IMAGE_IO_COMPRESSION_C8; + } + else if (strncmp(compression, "I1", 2) == 0) + { + nitf->compression = NITF_IMAGE_IO_COMPRESSION_I1; + } + else if (strncmp(compression, "M1", 2) == 0) + { + nitf->compression = NITF_IMAGE_IO_COMPRESSION_M1; + } + else if (strncmp(compression, "M3", 2) == 0) + { + nitf->compression = NITF_IMAGE_IO_COMPRESSION_M3; + } + else if (strncmp(compression, "M4", 2) == 0) + { + nitf->compression = NITF_IMAGE_IO_COMPRESSION_M4; + } + else if (strncmp(compression, "M5", 2) == 0) + { + nitf->compression = NITF_IMAGE_IO_COMPRESSION_M5; + } + else if (strncmp(compression, "M8", 2) == 0) + { + nitf->compression = NITF_IMAGE_IO_COMPRESSION_M8; + } + else + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_READING_FROM_FILE, + "Invalid compression type %s", compression); + return NITF_FAILURE; + } + + return NITF_SUCCESS; +} + +/*======================== nitf_ImageIO_decodeBlockingMode ===================*/ + +NITFPRIV(int) nitf_ImageIO_decodeBlockingMode(_nitf_ImageIO* nitf, + const nitf_ImageSubheader *subhdr, + nitf_Error* error) +{ + const char blockingMode = subhdr->imageMode->raw[0]; + + if (blockingMode == 'B') + { + nitf->blockingMode = NITF_IMAGE_IO_BLOCKING_MODE_B; + nitf->oneBand = 0; + nitf->vtbl.setup = nitf_ImageIO_setup_SBR; + nitf->vtbl.reader = NULL; + nitf->vtbl.writer = NULL; + nitf->vtbl.done = nitf_ImageIO_done_SBR; + } + else if (blockingMode == 'P') + { + if (nitf->numBands == 3 + && strncmp("RGB", subhdr->imageRepresentation->raw, 3) == 0 + && nitf->pixel.bytes == 1 + && (nitf->compression + & (NITF_IMAGE_IO_COMPRESSION_NC + | NITF_IMAGE_IO_COMPRESSION_NM))) + { + nitf->blockingMode = NITF_IMAGE_IO_BLOCKING_MODE_RGB24; + /* now, we fake the nbands and bytes */ + nitf->pixel.bytes *= nitf->numBands; + nitf->numBands = 1; + nitf->vtbl.setup = nitf_ImageIO_setup_SBR; + nitf->vtbl.done = nitf_ImageIO_setup_SBR; + } + else if (nitf->numBands == 2 + && ((subhdr->bandInfo[0]->subcategory->raw[0] == 'I' + && subhdr->bandInfo[1]->subcategory->raw[0] == 'Q')) + && (nitf->compression + & (NITF_IMAGE_IO_COMPRESSION_NC + | NITF_IMAGE_IO_COMPRESSION_NM))) + { + nitf->blockingMode = NITF_IMAGE_IO_BLOCKING_MODE_IQ; + /* now, we fake the nbands and bytes */ + nitf->pixel.bytes *= nitf->numBands; + nitf->numBands = 1; + nitf->vtbl.setup = nitf_ImageIO_setup_SBR; + nitf->vtbl.done = nitf_ImageIO_setup_SBR; + /* changing the unformat will only matters on LE systems + * this is required to do proper byte-swapping + */ + if (nitf->vtbl.unformat) + { + switch (nitf->pixel.bytes) + { + case 16: + nitf->vtbl.unformat = nitf_ImageIO_swapOnly_16c; + break; + case 8: + nitf->vtbl.unformat = nitf_ImageIO_swapOnly_8c; + break; + case 4: + nitf->vtbl.unformat = nitf_ImageIO_swapOnly_4c; + break; + case 2: + nitf->vtbl.unformat = NULL; + break; + default: + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_READING_FROM_FILE, + "Invalid number of bytes in complex data %d", nitf->pixel.bytes); + return NITF_FAILURE; + } + } + } + else + { + nitf->blockingMode = NITF_IMAGE_IO_BLOCKING_MODE_P; + nitf->vtbl.setup = nitf_ImageIO_setup_P; + nitf->vtbl.done = nitf_ImageIO_setup_P; + } + + nitf->oneBand = 0; + nitf->vtbl.reader = NULL; + nitf->vtbl.writer = NULL; + } + else if (blockingMode == 'R') + { + nitf->blockingMode = NITF_IMAGE_IO_BLOCKING_MODE_R; + nitf->oneBand = 0; + nitf->vtbl.setup = nitf_ImageIO_setup_SBR; + nitf->vtbl.reader = NULL; + nitf->vtbl.writer = NULL; + nitf->vtbl.done = nitf_ImageIO_done_SBR; + } + else if (blockingMode == 'S') + { + nitf->blockingMode = NITF_IMAGE_IO_BLOCKING_MODE_S; + nitf->oneBand = 1; + nitf->vtbl.setup = nitf_ImageIO_setup_SBR; + nitf->vtbl.reader = NULL; + nitf->vtbl.writer = NULL; + nitf->vtbl.done = nitf_ImageIO_done_SBR; + } + else + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_READING_FROM_FILE, + "Invalid blocking mode %c", blockingMode); + return NITF_FAILURE; + } + + /* Check for unimplemented blocking mode */ + if (nitf->vtbl.setup == NULL) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_READING_FROM_FILE, + "Unimplemented blocking mode %c", blockingMode); + return NITF_FAILURE; + } + + return NITF_SUCCESS; +} + +NITFPRIV(void) nitf_ImageIO_setIO(_nitf_ImageIO * nitf) +{ + + /* For now, used uncached reading for uncompressed images */ + + if ((nitf->pixel.type != NITF_IMAGE_IO_PIXEL_TYPE_B) + && (nitf->pixel.type != NITF_IMAGE_IO_PIXEL_TYPE_12) + && (nitf->compression & NITF_IMAGE_IO_NO_COMPRESSION)) + { + nitf->vtbl.reader = nitf_ImageIO_uncachedReader; + nitf->vtbl.writer = nitf_ImageIO_uncachedWriter; + } + else + { + nitf->vtbl.reader = nitf_ImageIO_cachedReader; + nitf->vtbl.writer = nitf_ImageIO_cachedWriter; + } + + return; +} + + + +/* Table used for selecting unformat format functions */ + +/* Pixel characteristics flags */ + +#define SWAP (0x00000001) +#define NOSWAP (0x00000002) +#define JUST (0x00000004) +#define NOJUST (0x00000008) +#define SIGN (0x00000010) +#define NOSIGN (0x00000020) + +#define BYTE_BASE (0x100) +#define BYTES_1 (BYTE_BASE << 1) +#define BYTES_2 (BYTE_BASE << 2) +#define BYTES_4 (BYTE_BASE << 4) +#define BYTES_8 (BYTE_BASE << 8) +#define BYTES_16 (BYTE_BASE << 16) + +typedef struct +{ + /* Pixel types mask */ + nitf_Uint32 types; + + /* Pixel size in byte flas */ + nitf_Uint32 bytes; + + /* Characteristics flag. swap */ + nitf_Uint32 swap; + + /* Characteristics flag. sign */ + nitf_Uint32 sign; + + /* Characteristics flag, just */ + nitf_Uint32 just; + + /* The function to use for unformat */ + _NITF_IMAGE_IO_UNFORMAT_FUNC unfmt; + + /* The function to use for format */ + _NITF_IMAGE_IO_FORMAT_FUNC fmt; +} +unformatTable; /* Also used for format */ + +#define NENTRIES 34 + +static unformatTable UNFORMAT_TABLE[NENTRIES] = +{ + /* Bi-endian full bits integers (NBPP=ABPP) + and right justified INT */ + { + NITF_IMAGE_IO_PIXEL_TYPE_B, BYTES_1, NOSWAP, NOSIGN, NOJUST, + NULL, NULL + }, + { /* 12-bit */ + NITF_IMAGE_IO_PIXEL_TYPE_12, + BYTES_2, NOSWAP, NOSIGN, NOJUST, + NULL, NULL + }, + { + NITF_IMAGE_IO_PIXEL_TYPE_INT | NITF_IMAGE_IO_PIXEL_TYPE_SI, + BYTES_1 | BYTES_2 | BYTES_4 | BYTES_8, NOSWAP, NOSIGN, NOJUST, + NULL, NULL + }, + /* Bi-endian reals */ + { + NITF_IMAGE_IO_PIXEL_TYPE_R, + BYTES_4 | BYTES_8, + NOSWAP, NOSIGN, NOJUST, + NULL, NULL + }, + /* Bi-endian complex */ + { + NITF_IMAGE_IO_PIXEL_TYPE_C, + BYTES_8 | BYTES_16 | BYTES_4, + NOSWAP, NOSIGN, NOJUST, + NULL, NULL + }, + /* Little-endian full bits integers (NBPP=ABPP), + right justified INT and floats */ + { + NITF_IMAGE_IO_PIXEL_TYPE_B, BYTES_1, SWAP, NOSIGN, NOJUST, + NULL, NULL + }, + { /* 12-bit */ + NITF_IMAGE_IO_PIXEL_TYPE_12, + BYTES_2, SWAP, NOSIGN, NOJUST, + NULL, NULL + }, + { + NITF_IMAGE_IO_PIXEL_TYPE_INT | NITF_IMAGE_IO_PIXEL_TYPE_SI, + BYTES_2, SWAP, NOSIGN, NOJUST, + nitf_ImageIO_swapOnly_2, nitf_ImageIO_swapOnly_2 + }, + + { + NITF_IMAGE_IO_PIXEL_TYPE_INT | NITF_IMAGE_IO_PIXEL_TYPE_SI | + NITF_IMAGE_IO_PIXEL_TYPE_R, + BYTES_4, SWAP, NOSIGN, NOJUST, + nitf_ImageIO_swapOnly_4, nitf_ImageIO_swapOnly_4 + }, + + { + NITF_IMAGE_IO_PIXEL_TYPE_INT | NITF_IMAGE_IO_PIXEL_TYPE_R, + BYTES_8, SWAP, NOSIGN, NOJUST, + nitf_ImageIO_swapOnly_8, nitf_ImageIO_swapOnly_8 + }, + + /* Little-endian complex */ + { + NITF_IMAGE_IO_PIXEL_TYPE_C, + BYTES_4, SWAP, NOSIGN, NOJUST, + nitf_ImageIO_swapOnly_4, nitf_ImageIO_swapOnly_4 + }, + { + NITF_IMAGE_IO_PIXEL_TYPE_C, + BYTES_8, SWAP, NOSIGN, NOJUST, + nitf_ImageIO_swapOnly_8c, nitf_ImageIO_swapOnly_8c + }, + + { + NITF_IMAGE_IO_PIXEL_TYPE_C, + BYTES_16, SWAP, NOSIGN, NOJUST, + nitf_ImageIO_swapOnly_16c, nitf_ImageIO_swapOnly_16c + }, + + /* Bi-endian INT, left justified */ + { + NITF_IMAGE_IO_PIXEL_TYPE_INT, BYTES_1, NOSWAP, NOSIGN, JUST, + nitf_ImageIO_unformatUShift_1, nitf_ImageIO_formatShift_1 + }, + { + NITF_IMAGE_IO_PIXEL_TYPE_INT, BYTES_2, NOSWAP, NOSIGN, JUST, + nitf_ImageIO_unformatUShift_2, nitf_ImageIO_formatShift_2 + }, + { + NITF_IMAGE_IO_PIXEL_TYPE_INT, BYTES_4, NOSWAP, NOSIGN, JUST, + nitf_ImageIO_unformatUShift_4, nitf_ImageIO_formatShift_4 + }, + { + NITF_IMAGE_IO_PIXEL_TYPE_INT, BYTES_8, NOSWAP, NOSIGN, JUST, + nitf_ImageIO_unformatUShift_8, nitf_ImageIO_formatShift_8 + }, + /* Little-endian INT, left justified */ + { + NITF_IMAGE_IO_PIXEL_TYPE_INT, BYTES_2, SWAP, NOSIGN, JUST, + nitf_ImageIO_unformatSwapUShift_2, nitf_ImageIO_formatShiftSwap_2 + }, + { + NITF_IMAGE_IO_PIXEL_TYPE_INT, BYTES_4, SWAP, NOSIGN, JUST, + nitf_ImageIO_unformatSwapUShift_4, nitf_ImageIO_formatShiftSwap_4 + }, + { + NITF_IMAGE_IO_PIXEL_TYPE_INT, BYTES_8, SWAP, NOSIGN, JUST, + nitf_ImageIO_unformatSwapUShift_8, nitf_ImageIO_formatShiftSwap_8 + }, + /* Bi-endian SI, left justified */ + { + NITF_IMAGE_IO_PIXEL_TYPE_SI, BYTES_1, NOSWAP, SIGN, JUST, + nitf_ImageIO_unformatShift_1, nitf_ImageIO_formatShift_1 + }, + { + NITF_IMAGE_IO_PIXEL_TYPE_SI, BYTES_2, NOSWAP, SIGN, JUST, + nitf_ImageIO_unformatShift_2, nitf_ImageIO_formatShift_2 + }, + { + NITF_IMAGE_IO_PIXEL_TYPE_SI, BYTES_4, NOSWAP, SIGN, JUST, + nitf_ImageIO_unformatShift_4, nitf_ImageIO_formatShift_4 + }, + { + NITF_IMAGE_IO_PIXEL_TYPE_SI, BYTES_8, NOSWAP, SIGN, JUST, + nitf_ImageIO_unformatShift_8, nitf_ImageIO_formatShift_8 + }, + /* Little-endian INT, left justified */ + { + NITF_IMAGE_IO_PIXEL_TYPE_SI, BYTES_2, SWAP, SIGN, JUST, + nitf_ImageIO_unformatSwapShift_2, nitf_ImageIO_formatShiftSwap_2 + }, + { + NITF_IMAGE_IO_PIXEL_TYPE_SI, BYTES_4, SWAP, SIGN, JUST, + nitf_ImageIO_unformatSwapShift_4, nitf_ImageIO_formatShiftSwap_4 + }, + { + NITF_IMAGE_IO_PIXEL_TYPE_SI, BYTES_8, SWAP, SIGN, JUST, + nitf_ImageIO_unformatSwapShift_8, nitf_ImageIO_formatShiftSwap_8 + }, + /* Bi-endian SI, right justified */ + { + NITF_IMAGE_IO_PIXEL_TYPE_SI, BYTES_1, NOSWAP, SIGN, NOJUST, + nitf_ImageIO_unformatExtend_1, nitf_ImageIO_formatMask_1 + }, + { + NITF_IMAGE_IO_PIXEL_TYPE_SI, BYTES_2, NOSWAP, SIGN, NOJUST, + nitf_ImageIO_unformatExtend_2, nitf_ImageIO_formatMask_2 + }, + { + NITF_IMAGE_IO_PIXEL_TYPE_SI, BYTES_4, NOSWAP, SIGN, NOJUST, + nitf_ImageIO_unformatExtend_4, nitf_ImageIO_formatMask_4 + }, + { + NITF_IMAGE_IO_PIXEL_TYPE_SI, BYTES_8, NOSWAP, SIGN, NOJUST, + nitf_ImageIO_unformatExtend_8, nitf_ImageIO_formatMask_8 + }, + /* Little-endian INT, right justified */ + { + NITF_IMAGE_IO_PIXEL_TYPE_SI, BYTES_2, SWAP, SIGN, NOJUST, + nitf_ImageIO_unformatSwapExtend_2, nitf_ImageIO_formatMaskSwap_2 + }, + { + NITF_IMAGE_IO_PIXEL_TYPE_SI, BYTES_4, SWAP, SIGN, NOJUST, + nitf_ImageIO_unformatSwapExtend_4, nitf_ImageIO_formatMaskSwap_4 + }, + { + NITF_IMAGE_IO_PIXEL_TYPE_SI, BYTES_8, SWAP, SIGN, NOJUST, + nitf_ImageIO_unformatSwapExtend_8, nitf_ImageIO_formatMaskSwap_8 + } +}; + +NITFPRIV(int) nitf_ImageIO_setPixelDef(_nitf_ImageIO * nitf, + char *pixelType, + nitf_Uint32 nBits, + nitf_Uint32 nBitsActual, + char *justify, + nitf_Error * error) +{ + char pixelTypeBuf[4]; /* Buffer for justified pixel type string */ + char *pixelTypePtr; /* Pointer into justified pixel type string */ + char *pixelTypeBufPtr; /* Pointer into justified pixel type buffer */ + nitf_Uint32 swap; /* Pixel characteristics flag, swap */ + nitf_Uint32 sign; /* Pixel characteristics flag, sign */ + nitf_Uint32 just; /* Pixel characteristics flag, just */ + int found; /* Found a valid unformat/format function */ + int i; + + /* Common field setup */ + sign = 0; + just = 0; + + nitf->pixel.bytes = NITF_NBPP_TO_BYTES(nBits); + nitf->pixel.shift = nBits - nBitsActual; + + if (nitf->pixel.bytes == 1) + nitf->pixel.swap = 0; + else + nitf->pixel.swap = !nitf_ImageIO_bigEndian(); + + if (nitf->pixel.swap) + swap = SWAP; + else + swap = NOSWAP; + + if ((justify[0] == 'L') && (nitf->pixel.shift != 0)) + just = JUST; + else + just = NOJUST; + + /* Sign extension */ + + sign = NOSIGN; + + /* Decode type string */ + + /* Eliminate spaces from string */ + + pixelTypePtr = pixelType; + pixelTypeBufPtr = pixelTypeBuf; + for (i = 0; i < 3; i++) + { + if (*pixelTypePtr == 0) + break; + + if (*pixelTypePtr != ' ') + *(pixelTypeBufPtr++) = *pixelTypePtr; + + pixelTypePtr += 1; + } + *pixelTypeBufPtr = 0; + + if ((nBits == 12) && (nBitsActual == 12)) + { + nitf->pixel.type = NITF_IMAGE_IO_PIXEL_TYPE_12; + nitf->pixel.bytes = 2; + nitf->pixel.shift = 0; + } + else if (strncmp(pixelType, "INT", 3) == 0) + { + nitf->pixel.type = NITF_IMAGE_IO_PIXEL_TYPE_INT; + } + else if (pixelType[0] == 'B') + { + nitf->pixel.type = NITF_IMAGE_IO_PIXEL_TYPE_B; + nitf->pixel.bytes = 1; + nitf->pixel.shift = 0; + } + else if (pixelType[0] == 'S' && pixelType[1] == 'I') + { + nitf->pixel.type = NITF_IMAGE_IO_PIXEL_TYPE_SI; + if (nitf->pixel.shift != 0) + sign = SIGN; + else + sign = NOSIGN; + } + else if (pixelType[0] == 'R') + { + nitf->pixel.type = NITF_IMAGE_IO_PIXEL_TYPE_R; + } + else if (pixelType[0] == 'C') + { + nitf->pixel.type = NITF_IMAGE_IO_PIXEL_TYPE_C; + } + else + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_READING_FROM_FILE, + "Invalid pixel type X %s", pixelType); + return NITF_FAILURE; + } + + /* Pixel unformat and format functions */ + + found = 0; + for (i = 0; i < NENTRIES; i++) + { + if ((nitf->pixel.type & UNFORMAT_TABLE[i].types) && + ((BYTE_BASE << nitf->pixel.bytes) & UNFORMAT_TABLE[i].bytes) && + (swap & UNFORMAT_TABLE[i].swap) && + (sign & UNFORMAT_TABLE[i].sign) && (just & UNFORMAT_TABLE[i].just)) + { + /* NOTE: When the imagery is compressed, the compressor/decompressor + * will take care of the endian swapping, so we don't want to + * perform any swapping in this case. We could just skip this + * entire for loop but don't in order to make sure the + * pixel type / # bits / justification combo is sane. */ + if (nitf->compression & NITF_IMAGE_IO_NO_COMPRESSION) + { + nitf->vtbl.unformat = UNFORMAT_TABLE[i].unfmt; + nitf->vtbl.format = UNFORMAT_TABLE[i].fmt; + } + found = 1; + break; + } + } + + if (!found) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_READING_FROM_FILE, + "Invalid pixel options: Type %s bits %ld justification %1s", + pixelType, nBits, justify); + return NITF_FAILURE; + } + + return NITF_SUCCESS; +} + + +NITFPRIV(void) nitf_ImageIO_setUnpack(_nitf_ImageIO * nitf) +{ + + /* + * Unpacking is required in three cases: + * + * Band interleved by pixel + * Binary pixels ("B" pixel type) + * Both of the above + */ + + /* None of the cases are implemented */ + nitf->vtbl.unpack = nitf->vtbl.pack = NULL; + + if (nitf->blockingMode == NITF_IMAGE_IO_BLOCKING_MODE_P && + (nitf->compression & NITF_IMAGE_IO_NO_COMPRESSION)) + { + switch (nitf->pixel.bytes) + { + case 1: + nitf->vtbl.unpack = nitf_ImageIO_unpack_P_1; + nitf->vtbl.pack = nitf_ImageIO_pack_P_1; + break; + case 2: + nitf->vtbl.unpack = nitf_ImageIO_unpack_P_2; + nitf->vtbl.pack = nitf_ImageIO_pack_P_2; + break; + case 4: + nitf->vtbl.unpack = nitf_ImageIO_unpack_P_4; + nitf->vtbl.pack = nitf_ImageIO_pack_P_4; + break; + case 8: + nitf->vtbl.unpack = nitf_ImageIO_unpack_P_8; + nitf->vtbl.pack = nitf_ImageIO_pack_P_8; + break; + default: /* Should never happen */ + case 16: + nitf->vtbl.unpack = nitf_ImageIO_unpack_P_16; + nitf->vtbl.pack = nitf_ImageIO_pack_P_16; + break; + } + } + + return; +} + +NITFPRIV(_nitf_ImageIOBlock **) nitf_ImageIO_allocBlockArray +(nitf_Uint32 numColumns, nitf_Uint32 numBands, nitf_Error * error) +{ + _nitf_ImageIOBlock **blockIOs; /*!< The result */ + _nitf_ImageIOBlock *blockIOPtr; /*!< The linear array of structures */ + nitf_Uint32 i; + + blockIOs = + (_nitf_ImageIOBlock **) NITF_MALLOC(sizeof(_nitf_ImageIOBlock *) * + numColumns); + if (blockIOs == NULL) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_MEMORY, + "Error allocating block I/O structure: %s", + NITF_STRERROR(NITF_ERRNO)); + return NITF_FAILURE; + } + + blockIOPtr = + (_nitf_ImageIOBlock *) NITF_MALLOC(sizeof(_nitf_ImageIOBlock) * + numColumns * numBands); + if (blockIOPtr == NULL) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_MEMORY, + "Error allocating block I/O structure: %s", + NITF_STRERROR(NITF_ERRNO)); + NITF_FREE(blockIOs); + return NITF_FAILURE; + } + + memset(blockIOPtr, 0, sizeof(_nitf_ImageIOBlock) * numColumns * numBands); + + for (i = 0; i < numColumns; i++) + { + blockIOs[i] = blockIOPtr; + blockIOPtr += numBands; + } + + return blockIOs; +} + + +NITFPRIV(void) nitf_ImageIO_freeBlockArray(_nitf_ImageIOBlock *** blockIOs) +{ + /* Dereferenced argument */ + _nitf_ImageIOBlock **blockIOsDeref; + + if (blockIOs == NULL) + return; + + blockIOsDeref = *blockIOs; + + if (blockIOsDeref[0] != NULL) + NITF_FREE(blockIOsDeref[0]); + + NITF_FREE(blockIOsDeref); + + *blockIOs = NULL; + return; +} + + +int nitf_ImageIO_setup_SBR(_nitf_ImageIOControl * cntl, nitf_Error * error) +{ + _nitf_ImageIO *nitf; /* Parent _nitf_ImageIO object */ + nitf_Uint32 startBlockRow; /* Starting blockRow */ + nitf_Uint32 endBlockRow; /* Ending blockRow */ + nitf_Uint32 startBlockCol; /* Starting blockCol */ + nitf_Uint32 endBlockCol; /* Ending blockCol */ + nitf_Uint32 nBlockCols; /* Number of blockCols */ + nitf_Uint32 startBlock; /* Block number of start block */ + nitf_Uint32 startRowInBlock0; /* Start row in the first block (pixels) */ + nitf_Uint32 startColumnInBlock0;/* Start column in the first block (pixels) */ + nitf_Uint32 residual; /* Partial sample columns previous block */ + nitf_Uint32 myResidual; /* Partial sample columns current block */ + nitf_Uint32 bytes; /* Bytes per pixel */ + _nitf_ImageIOBlock **blockIOs;/* The block I/O control structures */ + _nitf_ImageIOBlock *blockIO; /* The current block I/O control structure */ + nitf_Uint32 columnCountFR; /* Remaining column transfer count (bytes) */ + nitf_Uint32 numColsFR; /* Total number of columns requested FR */ + nitf_Uint32 startRowThisBlock; /* Start row for current block (pixels) */ + /* Start column for current block (pixels) */ + nitf_Uint32 startColumnThisBlock; + nitf_Uint32 blockNumber; /* Current block number */ + nitf_Uint32 userOff; /* Offsets into user buffers */ + nitf_Uint32 bandCnt; /* Number of bands in the read */ + nitf_Uint32 bandIdx; /* Current band index */ + nitf_Uint32 blockIdx; /* Current block index */ + nitf_Uint32 band; /* Current band */ + nitf_Uint32 modeBlockBaseOffset; /* Block pixel offset based on mode */ + nitf_Uint32 modeMaskOffset; /* Mask offset based on mode */ + nitf_Uint8 *writeBuffer; /* Write buffer */ + nitf_Uint8 *readBuffer; /* Read buffer */ + nitf_Uint8 blockColIdx; /* Current block column index */ + nitf_Uint8 *cacheBuffer; /* Current cach buffer */ + NITF_BOOL freeCacheBuffer; /* Sets block control free flag */ + /* Resets freeCacheBuffer flag */ + NITF_BOOL freeCacheBufferReset; + + nitf = cntl->nitf; + + /* + BlockRows and BlockCols variables manipulate block row and column indexes. + They have units of blocks and are used to calculate the start block number + and other block mask indexes and increments. + */ + + /* + * Calculate block row and column values + * + * The sub image row and column sizes are at down-sampled resolution but most + * of the calculation require full resolution. Full resolution count are + * obtained by multiplying by the pixel skips + * + * The tests applied to endBlockRow and endBlockColumn are looking for the case + * where the last down-sample neighborhood in the subwindow extends paritally + * beyond the edge of the image (right or bottom edge). This case is the + * exception to the rule that the request subwindow must be entirely in the + * image. In this case the end block calculation gives a block row or column + * out of range. + * + */ + + startBlockRow = cntl->row / nitf->numRowsPerBlock; + endBlockRow = (cntl->numRows * (cntl->rowSkip) + cntl->row - 1) / + nitf->numRowsPerBlock; + if (endBlockRow >= nitf->nBlocksPerRow) + endBlockRow -= 1; + + startBlockCol = cntl->column / nitf->numColumnsPerBlock; + endBlockCol = (cntl->numColumns * (cntl->columnSkip) + cntl->column - 1) / + nitf->numColumnsPerBlock; + if (endBlockCol >= nitf->nBlocksPerRow) + endBlockCol -= 1; + + nBlockCols = endBlockCol - startBlockCol + 1; + startBlock = startBlockRow * nitf->nBlocksPerRow + startBlockCol; + + startRowInBlock0 = cntl->row - startBlockRow * nitf->numRowsPerBlock; + startColumnInBlock0 = cntl->column - startBlockCol * nitf->numColumnsPerBlock; + + /* + Initialize increment values. For writing, the user buffer is not + used as the write buffer, so the buffer is not incremented + */ + + bytes = nitf->pixel.bytes; + cntl->numberInc = nitf->nBlocksPerRow; + cntl->userInc = cntl->numColumns * bytes; + if (cntl->reading) + { + if (cntl->downSampling) + cntl->bufferInc = + (nitf->numColumnsPerBlock + cntl->columnSkip) * bytes; + else + /* FR == DR */ + cntl->bufferInc = cntl->userInc; + } + else + cntl->bufferInc = 0; + + /* Create the block I/O structures */ + + bandCnt = cntl->numBandSubset; + + blockIOs = nitf_ImageIO_allocBlockArray(nBlockCols, bandCnt, error); + if (blockIOs == NULL) + return NITF_FAILURE; + + /* Set-up BlockIO's for each band */ + + cntl->nBlockIO = nBlockCols * bandCnt; + cntl->blockIO = blockIOs; + numColsFR = cntl->numColumns * (cntl->columnSkip); + columnCountFR = numColsFR; + startRowThisBlock = startRowInBlock0; + startColumnThisBlock = startColumnInBlock0; + residual = 0; /* Residual from block -1 is 0 */ + myResidual = 0; /* Avoids an uninitialized variable warning */ + blockNumber = startBlock; + + /* + * Allocate write buffer if writing or allocate read buffer if reading + * with down-sample + */ + + writeBuffer = NULL; /* Avoids uninitialized variable warning */ + readBuffer = NULL; /* Avoids uninitialized variable warning */ + if (cntl->reading) + { + if (cntl->downSampling) + { + /* + * The buffer should contain one sample window + * height rows of the width of a block plus one + * sample window width. The extra width is used to construct + * neighborhoods that are split across blocks. + * There has to be one buffer per band since the band loop + * is inside the row loop and a down-sample height + * number of rows must be accumulated before + * you can reuse the buffer. + */ + readBuffer = (nitf_Uint8 *) NITF_MALLOC((cntl->rowSkip) * + (nitf->numColumnsPerBlock + + cntl->columnSkip) * + bytes * bandCnt); + if (readBuffer == NULL) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_MEMORY, + "Error allocating read buffer: %s", + NITF_STRERROR(NITF_ERRNO)); + return NITF_FAILURE; + } + } + } + else + { + writeBuffer = + (nitf_Uint8 *) NITF_MALLOC(nitf->numColumnsPerBlock * bytes); + if (writeBuffer == NULL) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_MEMORY, + "Error allocating write buffer: %s", + NITF_STRERROR(NITF_ERRNO)); + if (readBuffer != NULL) + NITF_FREE(readBuffer); + return NITF_FAILURE; + } + } + + blockIO = &(blockIOs[0][0]); /* Eliminates spurious warning */ + userOff = 0; + blockColIdx = 0; + for (blockIdx = 0; blockIdx < nBlockCols; blockIdx++) + { + /* + * The write cach set-up requires that a buffer be allocated + * for each block I/O for mode S but all block I/O from the + * same column share the same buffer. The block control structure + * freeFlag tells the destructor when to free the buffers so as + * not to double free a buffer. This is the reason for the flag + * variables + */ + + freeCacheBuffer = 1; /* Always allocate first band */ + freeCacheBufferReset = 1; /* Do allocate after first band */ + if ((nitf->blockingMode != NITF_IMAGE_IO_BLOCKING_MODE_S) + && nitf->cachedWriteFlag) + { + cacheBuffer = + (nitf_Uint8 *) NITF_MALLOC(nitf->blockSize); + if (cacheBuffer == NULL) + { + nitf_Error_initf(error, NITF_CTXT, + NITF_ERR_MEMORY, + "Error allocating block buffer: %s", + NITF_STRERROR(NITF_ERRNO)); + return NITF_FAILURE; + } + freeCacheBufferReset = 1; /* Do not allocate after first band */ + } + else + cacheBuffer = NULL; /* This is meaningless */ + + for (bandIdx = 0; bandIdx < bandCnt; bandIdx++) + { + band = cntl->bandSubset[bandIdx]; + if ((nitf->blockingMode == NITF_IMAGE_IO_BLOCKING_MODE_S) + && freeCacheBuffer && nitf->cachedWriteFlag) + { + cacheBuffer = + (nitf_Uint8 *) NITF_MALLOC(nitf->blockSize); + if (cacheBuffer == NULL) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_MEMORY, + "Error allocating block buffer: %s", + NITF_STRERROR(NITF_ERRNO)); + return NITF_FAILURE; + } + } + + blockIO = &(blockIOs[blockIdx][bandIdx]); + if (nitf->blockingMode == NITF_IMAGE_IO_BLOCKING_MODE_S) + { + cntl->blockOffsetInc = nitf->numColumnsPerBlock * bytes; + modeBlockBaseOffset = 0; + modeMaskOffset = + band * nitf->nBlocksPerRow * nitf->nBlocksPerColumn; + blockIO->blockOffset.orig = + modeBlockBaseOffset + startColumnThisBlock * bytes; + + blockIO->blockOffset.mark = + blockIO->blockOffset.orig + + ((nitf_Uint64) startRowThisBlock) * + ((nitf_Uint64) nitf->numColumnsPerBlock) * + ((nitf_Uint64) bytes); + } + else if (nitf->blockingMode == NITF_IMAGE_IO_BLOCKING_MODE_B) + { + cntl->blockOffsetInc = nitf->numColumnsPerBlock * bytes; + modeBlockBaseOffset = + band * nitf->numColumnsPerBlock * nitf->numRowsPerBlock * + bytes; + modeMaskOffset = 0; + blockIO->blockOffset.orig = + modeBlockBaseOffset + startColumnThisBlock * bytes; + + blockIO->blockOffset.mark = + blockIO->blockOffset.orig + + ((nitf_Uint64) startRowThisBlock) * + ((nitf_Uint64) nitf->numColumnsPerBlock) * + ((nitf_Uint64) bytes); + } + else /* IMODE == "R" */ + { + cntl->blockOffsetInc = + nitf->numColumnsPerBlock * (nitf->numBands) * bytes; + modeBlockBaseOffset = band * nitf->numColumnsPerBlock * bytes; + modeMaskOffset = 0; + blockIO->blockOffset.orig = + modeBlockBaseOffset + startColumnThisBlock * bytes; + + blockIO->blockOffset.mark = + blockIO->blockOffset.orig + + ((nitf_Uint64) startRowThisBlock) * + ((nitf_Uint64) nitf->numColumnsPerBlock) * + ((nitf_Uint64) nitf->numBands) * + ((nitf_Uint64) bytes); + } + + blockIO->cntl = cntl; + blockIO->band = band; + blockIO->doIO = 1; + blockIO->number = blockNumber; + /* + * See description of _nitf_ImageIOControl for an + * explaination of the - 1 + */ + blockIO->rowsUntil = nitf->numRowsPerBlock - startRowInBlock0 - 1; + blockIO->blockMask = nitf->blockMask + modeMaskOffset; + blockIO->padMask = nitf->padMask + modeMaskOffset; + blockIO->imageDataOffset = blockIO->blockMask[blockNumber]; + blockIO->pixelCountFR = + (nitf->numColumnsPerBlock - startColumnThisBlock); + /* Last block may not span full block */ + if (blockIO->pixelCountFR > columnCountFR) + blockIO->pixelCountFR = columnCountFR; + blockIO->readCount = blockIO->pixelCountFR * bytes; + blockIO->padColumnCount = 0; + blockIO->padRowCount = 0; + blockIO->currentRow = cntl->row; + + /* Calculate the block column's residual and myResidual */ + + if (residual == 0) + blockIO->sampleStartColumn = 0; + else + blockIO->sampleStartColumn = cntl->columnSkip - residual; + + blockIO->pixelCountDR = + (blockIO->pixelCountFR - + blockIO->sampleStartColumn) / (cntl->columnSkip); + /* + * If there is a pixel split between this and the + * previous block, add one to the pixel count size + * the split pixel is precessed this block. A start + * column not zero indicates this + */ + if (blockIO->sampleStartColumn > 0) + blockIO->pixelCountDR += 1; + + /* + * Only update residual once per block column and only + * if down-sampling. The last column block is a special + * case because the normal myResidual calculation is based + * on read count which is not the right value in this + * case. myResidual only needs to be updated for the first + * band in a block column since the value will be the same + * for each band but this ad + */ + + blockIO->residual = residual; + if (bandIdx == 0) + { + if (blockColIdx != (nBlockCols - 1)) + { + myResidual = + (blockIO->pixelCountFR - + blockIO->sampleStartColumn) % cntl->columnSkip; + } + else + { + if (cntl->column + numColsFR > nitf->numColumns) + myResidual = + cntl->column + numColsFR - nitf->numColumns; + else + myResidual = 0; + } + } + + /* + * If there is a partial sample window at the end of the + * line that extends + * beyond the physical block size, the DR count must be + * incremented to account for this last partial neighborhood. + */ + if (cntl->downSampling && (blockColIdx == (nBlockCols - 1)) && + (cntl->column + numColsFR > nitf->numColumnsActual)) + blockIO->pixelCountDR += 1; + + if ((bandIdx >= (bandCnt - 1)) && cntl->downSampling) + { + blockColIdx += 1; + residual = myResidual; + } + blockIO->myResidual = myResidual; + + blockIO->formatCount = blockIO->pixelCountDR * (cntl->columnSkip); + + /* + * The user and buffer fields will be the same for reading + * but a separate buffer is required for writing. The data is + * copied into the buffer so that the format function does not + * modifiy the user supplied data. This is not required for + * reading. The write buffer only needs enough save for one write. + */ + + if (cntl->userBase != NULL) + blockIO->user.buffer = cntl->userBase[bandIdx]; + else + blockIO->user.buffer = NULL; + blockIO->user.offset.mark = userOff; + blockIO->user.offset.orig = userOff; + + if (cntl->reading) + { + if (cntl->downSampling) + { + /* There is a different buffer for each band */ + blockIO->rwBuffer.buffer = readBuffer + + (cntl->rowSkip) * (nitf->numColumnsPerBlock + + cntl->columnSkip) * bytes * bandIdx; + blockIO->rwBuffer.offset.mark = blockIO->residual * bytes; + blockIO->rwBuffer.offset.orig = blockIO->residual * bytes; + blockIO->userEqBuffer = 0; + } + else + { + /* Read directly into user buffer */ + blockIO->rwBuffer.buffer = blockIO->user.buffer; + /* FR == DR */ + blockIO->rwBuffer.offset.mark = userOff; + blockIO->rwBuffer.offset.orig = userOff; + blockIO->userEqBuffer = 1; + } + } + else + { + /* Allocate a buffer shared by all block I/O's */ + blockIO->rwBuffer.buffer = writeBuffer; + blockIO->rwBuffer.offset.mark = 0; + blockIO->rwBuffer.offset.orig = 0; + blockIO->userEqBuffer = 0; + } + + /* + * Initialize the unpacked buffer, for SBR modes this + * is the read/write buffer + */ + cntl->unpackedInc = cntl->bufferInc; + blockIO->unpacked.buffer = blockIO->rwBuffer.buffer; + blockIO->unpacked.offset.mark = blockIO->rwBuffer.offset.mark; + blockIO->unpacked.offset.orig = blockIO->rwBuffer.offset.orig; + blockIO->unpackedNoFree = 1; + + /* + * Initialize block control (used for cached writes) + */ + blockIO->blockControl.number = NITF_IMAGE_IO_NO_BLOCK; + blockIO->blockControl.freeFlag = freeCacheBuffer; + freeCacheBuffer = freeCacheBufferReset; + blockIO->blockControl.block = cacheBuffer; + } + + userOff += blockIO->pixelCountDR * bytes; + + startColumnThisBlock = 0; + + /* + * Start at the begining after + * first block column + */ + columnCountFR -= blockIO->pixelCountFR; + blockNumber += 1; + } + + /* Set pad buffer size */ + + cntl->padBuffer = NULL; /* Created the first time it is used */ + if (cntl->reading) + { + if (cntl->numColumns < nitf->numColumnsPerBlock) + cntl->padBufferSize = + cntl->numColumns * nitf->pixel.bytes * cntl->columnSkip; + else + cntl->padBufferSize = nitf->numColumnsPerBlock * nitf->pixel.bytes; + } + else + cntl->padBufferSize = nitf->numColumnsPerBlock * nitf->pixel.bytes; + + /* + * Set-up last block column for column pad if writing + * + * Writing of pad pixels is required if the actual number of columns is + * greater than the NITF header number of columns field and the sub-image + * being written includes the last pixel in the line. + * + * If all of this is TRUE, then set the padColumnCount field in the + * blocks that are at the end of the rows. There will be one per band. + * + * The actual row length will be bigger if the block size is not an integral + * multiple of the row length. + * + */ + + if (!(cntl->reading) + && (nitf->numColumnsActual > nitf->numColumns) + && (cntl->column + cntl->numColumns >= nitf->numColumns)) + { + /* The relevent blockIO's are at the end of the row + * (the last block column) + */ + for (bandIdx = 0; bandIdx < bandCnt; bandIdx++) + { + blockIO = &(cntl->blockIO[nBlockCols - 1][bandIdx]); + blockIO->padColumnCount = + (nitf->numColumnsActual - nitf->numColumns) * bytes; + blockIO += nBlockCols; + } + } + + /* + * Set-up block columns for row pad if writing + * + * Writing of pad pixels is also required if the actual number of rows is + * greater than the NITF header number of rows field and the sub-image + * being written includes the last row in the image. + * + * If all of this is TRUE, then set the padRowCount field + * in all of the blocks. + * Since the block structures represent columns of blocks, + * all of the columns + * will include the end of the image if any do. + */ + if (!(cntl->reading) + && (nitf->numRowsActual > nitf->numRows) + && (cntl->row + cntl->numRows >= nitf->numRows)) + { + blockIO = &(cntl->blockIO[0][0]); + for (blockIdx = 0; blockIdx < cntl->nBlockIO; blockIdx++) + { + if (nitf->blockingMode == NITF_IMAGE_IO_BLOCKING_MODE_R) + blockIO->padRowCount = + (nitf->numRowsActual - nitf->numRows) * (nitf->numBands); + else + blockIO->padRowCount = nitf->numRowsActual - nitf->numRows; + + blockIO += 1; + } + } + + cntl->ioCount = (size_t)nBlockCols * nitf->numBands * cntl->numRows; + return NITF_SUCCESS; +} + +int nitf_ImageIO_done_SBR(_nitf_ImageIOControl * cntl, nitf_Error * error) +{ + /* Silence compiler warnings about unused variables */ + (void)cntl; + (void)error; + return NITF_SUCCESS; +} + + +int nitf_ImageIO_setup_P(_nitf_ImageIOControl * cntl, nitf_Error * error) +{ + _nitf_ImageIO *nitf = NULL; /* Parent _nitf_ImageIO object */ + nitf_Uint32 startBlockRow; /* Starting blockRow */ + nitf_Uint32 endBlockRow; /* Ending blockRow */ + nitf_Uint32 startBlockCol; /* Starting blockCol */ + nitf_Uint32 endBlockCol; /* Ending blockCol */ + nitf_Uint32 nBlockCols; /* Number of blockCols */ + nitf_Uint32 startBlock; /* Block number of start block */ + nitf_Uint32 startRowInBlock0; /* Start row in the first block (pixels) */ + nitf_Uint32 startColumnInBlock0; /* Start column in the first block (pixels) */ + nitf_Uint32 residual; /* Partial sample columns previous block */ + nitf_Uint32 myResidual; /* Partial sample columns current block */ + nitf_Uint32 bytes; /* Bytes per pixel */ + _nitf_ImageIOBlock **blockIOs = NULL;/* The block I/O control structures */ + _nitf_ImageIOBlock *blockIO = NULL; /* The current block I/O control structure */ + nitf_Uint32 columnCountFR; /* Remaining column transfer count (bytes) */ + nitf_Uint32 numColsFR; /* Total number of columns requested FR */ + nitf_Uint32 startRowThisBlock; /* Start row for current block (pixels) */ + /* Start column for current block (pixels) */ + nitf_Uint32 startColumnThisBlock; + nitf_Uint32 blockNumber; /* Current block number */ + nitf_Uint32 userOff; /* Offsets into user buffers */ + nitf_Uint32 bandCnt; /* Number of bands in the read */ + nitf_Uint32 bandIdx; /* Current band index */ + nitf_Uint32 blockIdx; /* Current block index */ + nitf_Uint32 band; /* Current band */ + nitf_Uint8 *ioBuffer = NULL; /* I/O buffer */ + nitf_Uint8 *unpackedBuffer = NULL; /* Unpacked data buffer */ + nitf_Uint8 blockColIdx; /* Current block column index */ + nitf_Uint8 *cacheBuffer = NULL; /* Current cach buffer */ + NITF_BOOL freeCacheBuffer; /* Sets block control free flag */ + /* Resets freeCacheBuffer flag */ + NITF_BOOL freeCacheBufferReset; + + nitf = cntl->nitf; + + /* + * BlockRows and BlockCols variables manipulate block row + * and column indexes. + * They have units of blocks and are used to calculate the + * start block number + * and other block mask indexes and increments. + */ + + /* + * Calculate block row and column values (see nitf_ImageIO_setup_SBR + * for more information + */ + startBlockRow = cntl->row / nitf->numRowsPerBlock; + endBlockRow = (cntl->numRows * (cntl->rowSkip) + cntl->row - 1) / + nitf->numRowsPerBlock; + if (endBlockRow >= nitf->nBlocksPerRow) + endBlockRow -= 1; + + startBlockCol = cntl->column / nitf->numColumnsPerBlock; + endBlockCol = (cntl->numColumns * (cntl->columnSkip) + cntl->column - 1) / + nitf->numColumnsPerBlock; + if (endBlockCol >= nitf->nBlocksPerRow) + endBlockCol -= 1; + + nBlockCols = endBlockCol - startBlockCol + 1; + startBlock = startBlockRow * nitf->nBlocksPerRow + startBlockCol; + + startRowInBlock0 = cntl->row - startBlockRow * nitf->numRowsPerBlock; + startColumnInBlock0 = cntl->column - startBlockCol * nitf->numColumnsPerBlock; + + /* + * Initialize increment values. For writing, the user buffer is not + * used as the write buffer, so the buffer is not incremented + */ + bytes = nitf->pixel.bytes; + cntl->numberInc = nitf->nBlocksPerRow; + cntl->blockOffsetInc = (nitf->numColumnsPerBlock) * (nitf->numBands) * bytes; + cntl->userInc = cntl->numColumns * bytes; + cntl->bufferInc = 0; + if (cntl->reading) + { + if (cntl->downSampling) + cntl->unpackedInc = + (nitf->numColumnsPerBlock + cntl->columnSkip) * bytes; + else + /* FR == DR */ + cntl->unpackedInc = cntl->userInc; + } + else + cntl->unpackedInc = 0; + + /* Create the block I/O structures */ + + bandCnt = cntl->numBandSubset; + + blockIOs = nitf_ImageIO_allocBlockArray(nBlockCols, bandCnt, error); + if (blockIOs == NULL) + return NITF_FAILURE; + + /* Set-up BlockIO's for each band */ + cntl->nBlockIO = nBlockCols * bandCnt; + cntl->blockIO = blockIOs; + columnCountFR = cntl->numColumns * (cntl->columnSkip); + numColsFR = cntl->numColumns * (cntl->columnSkip); + startRowThisBlock = startRowInBlock0; + startColumnThisBlock = startColumnInBlock0; + residual = 0; /* Residual from block -1 is 0 */ + myResidual = 0; /* Avoids an uninitialized variable warning */ + blockNumber = startBlock; + + /* Allocate I/O and unpacked buffer */ + if (cntl->downSampling) + { + unpackedBuffer = (nitf_Uint8 *) NITF_MALLOC((nitf->numColumnsPerBlock + + cntl->columnSkip) * + (nitf->numBands) * + (cntl->rowSkip) * + bytes); + if (unpackedBuffer == NULL) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_MEMORY, + "Error allocating unpacked data buffer: %s", + NITF_STRERROR(NITF_ERRNO)); + return NITF_FAILURE; + } + } + else + unpackedBuffer = NULL; + + + if (nitf->compression & NITF_IMAGE_IO_NO_COMPRESSION) + { + ioBuffer = (nitf_Uint8 *) NITF_MALLOC(nitf->numColumnsPerBlock * + nitf->numBands * bytes); + if (ioBuffer == NULL) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_MEMORY, + "Error allocating I/O buffer: %s", + NITF_STRERROR(NITF_ERRNO)); + if (unpackedBuffer != NULL) + NITF_FREE(unpackedBuffer); + return NITF_FAILURE; + } + } + + /* Initialize blocks */ + blockIO = &(blockIOs[0][0]); /* Eliminates spurious warning */ + userOff = 0; + blockColIdx = 0; + for (blockIdx = 0; blockIdx < nBlockCols; blockIdx++) + { + freeCacheBuffer = 1; /* Always allocate first band */ + freeCacheBufferReset = 0; /* Do not allocate after first band */ + if (nitf->cachedWriteFlag) + { + cacheBuffer = + (nitf_Uint8 *) NITF_MALLOC(nitf->blockSize); + if (cacheBuffer == NULL) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_MEMORY, + "Error allocating block buffer: %s", + NITF_STRERROR(NITF_ERRNO)); + return NITF_FAILURE; + } + } + + for (bandIdx = 0; bandIdx < bandCnt; bandIdx++) + { + band = cntl->bandSubset[bandIdx]; + + blockIO = &(blockIOs[blockIdx][bandIdx]); + blockIO->cntl = cntl; + blockIO->band = band; + + /* + * When reading, only the first blockIO in + * each column does the actual read, + * the rest just unpack + * + * When writing, only the last blockIO in each + * column does the actual write, + * the rest just pack + */ + if (cntl->reading) + blockIO->doIO = (bandIdx == 0) ? 1 : 0; + else + blockIO->doIO = (bandIdx == (nitf->numBands - 1)) ? 1 : 0; + blockIO->number = blockNumber; + /* + * See description of _nitf_ImageIOControl for an + * explaination of the - 1 + */ + blockIO->rowsUntil = nitf->numRowsPerBlock - startRowInBlock0 - 1; + blockIO->blockMask = nitf->blockMask; + blockIO->padMask = nitf->padMask; + blockIO->imageDataOffset = blockIO->blockMask[blockNumber]; + blockIO->blockOffset.orig = + startColumnThisBlock * (nitf->numBands) * bytes; + + blockIO->blockOffset.mark = + blockIO->blockOffset.orig + + ((nitf_Uint64) startRowThisBlock) * + ((nitf_Uint64) nitf->numColumnsPerBlock) * + ((nitf_Uint64) nitf->numBands) * + ((nitf_Uint64) bytes); + + blockIO->pixelCountFR = + (nitf->numColumnsPerBlock - startColumnThisBlock); + + /* Last block may not span full block */ + if (blockIO->pixelCountFR > columnCountFR) + blockIO->pixelCountFR = columnCountFR; + + blockIO->readCount = + blockIO->pixelCountFR * (nitf->numBands) * bytes; + blockIO->padColumnCount = 0; + blockIO->padRowCount = 0; + blockIO->currentRow = cntl->row; + + /* Calculate the block column's residual and myResidual */ + if (residual == 0) + blockIO->sampleStartColumn = 0; + else + blockIO->sampleStartColumn = cntl->columnSkip - residual; + + blockIO->pixelCountDR = + (blockIO->pixelCountFR - + blockIO->sampleStartColumn) / (cntl->columnSkip); + /* + * If there is a pixel split between this and the + * previous block, add one + * to the pixel count size the split pixel is + * precessed this block. A start + * column not zero indicates this + */ + + if (blockIO->sampleStartColumn > 0) + blockIO->pixelCountDR += 1; + + /* + * Only update residual once per block column and + * only if down-sampling. The last column block is a + * special case because the normal myResidual + * calculation is based on read count which is not the + * right value in this case. myResidual only needs to be + * updated for the first band in a block + * column since the value will be the same for + * each band but this ad + */ + + blockIO->residual = residual; + if (cntl->downSampling) + { + if (bandIdx == 0) + { + if (blockColIdx != (nBlockCols - 1)) + { + myResidual = + (blockIO->pixelCountFR - + blockIO->sampleStartColumn) % cntl->columnSkip; + } + else + { + if (cntl->column + numColsFR > nitf->numColumns) + myResidual = + cntl->column + numColsFR - nitf->numColumns; + else + myResidual = 0; + } + } + /* + * If there is a partial sample window at the end + * of the line that extends + * beyond the physical block size, the DR count + * must be incremented to + * account for this last partial neighborhood. + */ + if ((blockColIdx == (nBlockCols - 1)) && + (cntl->column + numColsFR > nitf->numColumnsActual)) + blockIO->pixelCountDR += 1; + + if (bandIdx >= (bandCnt - 1)) + { + blockColIdx += 1; + residual = myResidual; + } + } + blockIO->myResidual = myResidual; + + if (cntl->downSampling) + blockIO->formatCount = + blockIO->pixelCountDR * (cntl->columnSkip); + else + blockIO->formatCount = blockIO->pixelCountFR * nitf->numBands; + + /* + * The user and buffer fields will be separate buffers since + * the amount read/written is nitf->numBands times more than + * is required for any one band due to the interleaving + * + * The bufferOffset field gives the spacing between bands + * in the read case and is set to 0 in the write case. + * + * For reading, the first read for a given row segment reads + * all of the bands for that segment. The initial offset of 0 + * for the first band is the correct + * buffer offset for the read. The pixel size times band offset + * then correctly line-up the start buffer for the unpack + * operations. + * + * For writing, the buffer offset should be zero since the + * last block IO does the write. The offsets need for the bands + * are calculated directly by the pack function. + */ + if (cntl->userBase != NULL) + blockIO->user.buffer = cntl->userBase[bandIdx]; + else + blockIO->user.buffer = NULL; + + + if (nitf->compression & NITF_IMAGE_IO_NO_COMPRESSION) + { + blockIO->rwBuffer.buffer = ioBuffer; + blockIO->userEqBuffer = 0; + } + else + { + /* Read directly into user buffer */ + blockIO->rwBuffer.buffer = blockIO->user.buffer; + cntl->bufferInc = cntl->blockOffsetInc; + blockIO->userEqBuffer = 1; + } + + blockIO->user.offset.mark = userOff; + blockIO->user.offset.orig = userOff; + if (cntl->reading) + { + blockIO->rwBuffer.offset.mark = bytes * band; + blockIO->rwBuffer.offset.orig = bytes * band; + } + else + { + blockIO->rwBuffer.offset.mark = 0; + blockIO->rwBuffer.offset.orig = 0; + } + + /* + * Initialize the unpacked buffer, for P modes this is the + * user buffer buffer unless there is down-sampling + */ + + /* + * Initialize the unpacked buffer, for P modes this + * is a separate buffer + */ + if (cntl->downSampling) + { + /* There is a different buffer for each band */ + blockIO->unpacked.buffer = unpackedBuffer + + (cntl->rowSkip) * (nitf->numColumnsPerBlock + + cntl->columnSkip) * bytes * band; + blockIO->unpacked.offset.mark = blockIO->residual * bytes; + blockIO->unpacked.offset.orig = blockIO->residual * bytes; + blockIO->unpackedNoFree = 0; + } + else + { + /* Read directly into user buffer */ + blockIO->unpacked.buffer = blockIO->user.buffer; + /* FR == DR */ + blockIO->unpacked.offset.mark = blockIO->user.offset.mark; + blockIO->unpacked.offset.orig = blockIO->user.offset.mark; + blockIO->unpackedNoFree = 1; + } + + /* + * Initialize block control (used for cached writes) + */ + blockIO->blockControl.number = NITF_IMAGE_IO_NO_BLOCK; + blockIO->blockControl.freeFlag = freeCacheBuffer; + freeCacheBuffer = freeCacheBufferReset; + blockIO->blockControl.block = cacheBuffer; + } + + userOff += blockIO->pixelCountDR * bytes; + startColumnThisBlock = 0; + /* + * Start at the begining after + * first block column + */ + columnCountFR -= blockIO->pixelCountFR; + blockNumber += 1; + } + + /* Set pad buffer size */ + + cntl->padBuffer = NULL; /* Created the first time it is used */ + if (cntl->reading) + { + if (cntl->numColumns < nitf->numColumnsPerBlock) + cntl->padBufferSize = cntl->numColumns * (nitf->numBands) * + (nitf->pixel.bytes * cntl->columnSkip); + else + cntl->padBufferSize = nitf->numColumnsPerBlock * + (nitf->numBands) * (nitf->pixel.bytes); + } + else + cntl->padBufferSize = + nitf->numColumnsPerBlock * (nitf->numBands) * nitf->pixel.bytes; + + /* + * Set-up last block column for column pad if writing + * + * Writing of pad pixels is required if the actual number of columns is + * greater than the NITF header number of columns field and the sub-image + * being written includes the last pixel in the line. + * + * If all of this is TRUE, then set the padColumnCount + * field in the blocks that + * are at the end of the rows. There will be one per band. + * + * The actual row length will be bigger if the block size is not an integral + * multiple of the row length. + * + */ + + if (!(cntl->reading) + && (nitf->numColumnsActual > nitf->numColumns) + && (cntl->column + cntl->numColumns >= nitf->numColumns)) + { + /* + * The relevent blockIO's are at the end of the row + * (the last block column) + */ + + for (bandIdx = 0; bandIdx < bandCnt; bandIdx++) + { + blockIO = &(cntl->blockIO[nBlockCols - 1][bandIdx]); + blockIO->padColumnCount = + (nitf->numColumnsActual - + nitf->numColumns) * (nitf->numBands) * bytes; + } + } + + /* + * Set-up block columns for row pad if writing + * + * Writing of pad pixels is also required if the actual number of rows is + * greater than the NITF header number of rows field and the sub-image + * being written includes the last row in the image. + * + * If all of this is TRUE, then set the padRowCount field in + * all of the blocks. + * Since the block structures represent columns of blocks, + * all of the columns + * will include the end of the image if any do. + */ + + if (!(cntl->reading) + && (nitf->numRowsActual > nitf->numRows) + && (cntl->row + cntl->numRows >= nitf->numRows)) + { + blockIO = &(cntl->blockIO[0][0]); + for (blockIdx = 0; blockIdx < cntl->nBlockIO; blockIdx++) + { + blockIO->padRowCount = nitf->numRowsActual - nitf->numRows; + blockIO += 1; + } + } + + cntl->ioCount = (size_t)nBlockCols * nitf->numBands * cntl->numRows; + return NITF_SUCCESS; +} + +int nitf_ImageIO_done_P(_nitf_ImageIOControl * cntl, nitf_Error * error) +{ + /* Silence compiler warnings about unused variables */ + (void)cntl; + (void)error; + return NITF_SUCCESS; +} + + +NITFPRIV(_nitf_ImageIOControl *) +nitf_ImageIOControl_construct(_nitf_ImageIO * nitf, + nitf_IOInterface* io, + nitf_Uint8 ** user, + nitf_SubWindow * subWindow, int reading, + nitf_Error * error) +{ + _nitf_ImageIOControl *cntl; /* The result */ + + cntl = + (_nitf_ImageIOControl *) NITF_MALLOC(sizeof(_nitf_ImageIOControl)); + if (cntl == NULL) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_MEMORY, + "Memory allocation error: %s", + NITF_STRERROR(NITF_ERRNO)); + return NULL; + } + /* Initialize all fields to 0 */ + memset(cntl, 0, sizeof(_nitf_ImageIOControl)); + + /* Set fields from arguments */ + cntl->nitf = nitf; + cntl->numRows = subWindow->numRows; + cntl->row = subWindow->startRow; + cntl->numColumns = subWindow->numCols; + cntl->column = subWindow->startCol; + if (subWindow->downsampler != NULL) + { + cntl->rowSkip = subWindow->downsampler->rowSkip; + cntl->columnSkip = subWindow->downsampler->colSkip; + } + else + { + cntl->rowSkip = 1; + cntl->columnSkip = 1; + } + cntl->downSampling = (cntl->rowSkip != 1) || (cntl->columnSkip != 1); + if (cntl->downSampling) + { + cntl->downSampleIn = + (NITF_DATA **) NITF_MALLOC(subWindow->numBands * + sizeof(nitf_Uint8 *)); + if (cntl->downSampleIn == NULL) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_MEMORY, + "Memory allocation error: %s", + NITF_STRERROR(NITF_ERRNO)); + return NULL; + } + cntl->downSampleOut = + (NITF_DATA **) NITF_MALLOC(subWindow->numBands * + sizeof(nitf_Uint8 *)); + if (cntl->downSampleOut == NULL) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_MEMORY, + "Memory allocation error: %s", + NITF_STRERROR(NITF_ERRNO)); + return NULL; + } + } + else + { + cntl->downSampleIn = NULL; + cntl->downSampleOut = NULL; + } + + cntl->bandSubset = + (nitf_Uint32 *) NITF_MALLOC(subWindow->numBands * + sizeof(nitf_Uint32)); + if (cntl->bandSubset == NULL) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_MEMORY, + "Memory allocation error: %s", + NITF_STRERROR(NITF_ERRNO)); + return NULL; + } + + if (subWindow->bandList != NULL) + memmove(cntl->bandSubset, subWindow->bandList, + subWindow->numBands * sizeof(nitf_Uint32)); + else if (subWindow->numBands == nitf->numBands) + { + nitf_Uint32 i; + for (i = 0; i < nitf->numBands; i++) + cntl->bandSubset[i] = i; + } + else + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_MEMORY, + "NULL band list with numBands not all bands"); + return NULL; + } + cntl->numBandSubset = subWindow->numBands; + cntl->userBase = user; + cntl->reading = reading; + + /* + * If writing, create masks and check for masked compression type + * A masked compression type requires block caching + */ + + if (!reading) + { + if ((nitf->blockMask == NULL) + && (!nitf_ImageIO_mkMasks(nitf, io, 0, error))) + { + nitf_ImageIOControl_destruct(&cntl); + return NULL; + } + + if ((nitf->compression & + (NITF_IMAGE_IO_COMPRESSION_NM + | NITF_IMAGE_IO_COMPRESSION_M1 + | NITF_IMAGE_IO_COMPRESSION_M3 + | NITF_IMAGE_IO_COMPRESSION_M4 + | NITF_IMAGE_IO_COMPRESSION_M5 + | NITF_IMAGE_IO_COMPRESSION_M8))) + nitf_ImageIO_setWriteCaching((nitf_ImageIO *) nitf, 1); + } + + /* + * Allocate column save buffer if down-sampling. The buffer is one + * sample window width by the full resolution request number of rows times + * the number of bands. Storage for each band is required because the band + * loop is inside the row loop + */ + + if (cntl->downSampling) + { + /* Full resolution */ + cntl->columnSave = + (nitf_Uint8 *) NITF_MALLOC((cntl->numRows) * (cntl->rowSkip) * + (cntl->columnSkip) * + (cntl->numBandSubset) * + (nitf->pixel.bytes)); + if (cntl->columnSave == NULL) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_MEMORY, + "Memory allocation error: %s", + NITF_STRERROR(NITF_ERRNO)); + return NULL; + } + } + + /* Call mode specific setup function */ + if (!(*(nitf->vtbl.setup)) (cntl, error)) + { + nitf_ImageIOControl_destruct(&cntl); + return NULL; + } + + if(nitf->compressor != NULL) + { + if(!(*(nitf->compressor->start))( + nitf->compressionControl, nitf->pixelBase, + nitf->dataLength - nitf->maskHeader.imageDataOffset, + nitf->blockMask,nitf->padMask, error) ) + { + nitf_ImageIO_destruct((void **) &nitf); + return NITF_FAILURE; + } + } + + cntl->padded = 0; + return cntl; +} + +NITFPRIV(void) nitf_ImageIOControl_destruct(_nitf_ImageIOControl ** cntl) +{ + _nitf_ImageIOBlock *blocks; /* Block I/Os as a linrar array */ + nitf_Uint32 i; + nitf_Uint32 nBlockCols; + + /* Actual object */ + _nitf_ImageIOControl *cntlActual; + + if (*cntl == NULL) + return; + + cntlActual = *cntl; + + /* Free fields */ + if (cntlActual->blockIO != NULL) + { + /* Free buffer */ + if (!(cntlActual->blockIO[0][0].userEqBuffer)) + if (cntlActual->blockIO[0][0].rwBuffer.buffer != NULL) + NITF_FREE(cntlActual->blockIO[0][0].rwBuffer.buffer); + + /* Free buffer */ + if (!(cntlActual->blockIO[0][0].unpackedNoFree)) + if (cntlActual->blockIO[0][0].unpacked.buffer != NULL) + NITF_FREE(cntlActual->blockIO[0][0].unpacked.buffer); + + /* + * Free block buffers if allocated + * This works because of how + * They are allocated + */ + nBlockCols = cntlActual->nBlockIO / cntlActual->numBandSubset; + blocks = &(cntlActual->blockIO[0][0]); + for (i = 0; i < nBlockCols; ++i) + { + if (blocks[i].blockControl.freeFlag) + { + NITF_FREE(blocks[i].blockControl.block); + } + } + + nitf_ImageIO_freeBlockArray(&(cntlActual->blockIO)); + } + + if (cntlActual->downSampleIn != NULL) + NITF_FREE(cntlActual->downSampleIn); + + if (cntlActual->downSampleOut != NULL) + NITF_FREE(cntlActual->downSampleOut); + + if (cntlActual->bandSubset != NULL) + NITF_FREE(cntlActual->bandSubset); + + if (cntlActual->padBuffer != NULL) + NITF_FREE(cntlActual->padBuffer); + + if (cntlActual->columnSave != NULL) + NITF_FREE(cntlActual->columnSave); + + NITF_FREE(cntlActual); + *cntl = NULL; + return; +} + +NITFPRIV(_nitf_ImageIOWriteControl *) +nitf_ImageIOWriteControl_construct(_nitf_ImageIOControl * cntl, + nitf_IOInterface* io, + _nitf_ImageIO_writeMethod method, + nitf_Error * error) +{ + /* The return value */ + _nitf_ImageIOWriteControl *result; + + /* Silence compiler warnings about unused variables */ + (void)io; + + result = (_nitf_ImageIOWriteControl *) + NITF_MALLOC(sizeof(_nitf_ImageIOWriteControl)); + if (result == NULL) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_MEMORY, + "Error allocating object: %s", + NITF_STRERROR(NITF_ERRNO)); + return NULL; + } + + /* Initialize fields */ + result->cntl = cntl; + result->method = method; + result->nextRow = 0; + return result; +} + +NITFPRIV(void) nitf_ImageIOWriteControl_destruct(_nitf_ImageIOWriteControl + ** cntl) +{ + NITF_FREE(*cntl); + *cntl = NULL; + return; +} + + +NITFPRIV(_nitf_ImageIOReadControl *) nitf_ImageIOReadControl_construct +(_nitf_ImageIOControl * cntl, nitf_SubWindow * subWindow, + nitf_Error * error) +{ + /* The return value */ + _nitf_ImageIOReadControl *result; + + /* Silence compiler warnings about unused variables */ + (void)subWindow; + + result = (_nitf_ImageIOReadControl *) + NITF_MALLOC(sizeof(_nitf_ImageIOReadControl)); + if (result == NULL) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_MEMORY, + "Error allocating object: %s", NITF_STRERROR(NITF_ERRNO)); + return NULL; + } + + /* Initialize fields */ + result->cntl = cntl; + + return result; +} + +NITFPRIV(void) nitf_ImageIOReadControl_destruct(_nitf_ImageIOReadControl ** + cntl) +{ + NITF_FREE(*cntl); + *cntl = NULL; + return; +} + + +NITFPRIV(int) nitf_ImageIO_bigEndian(void) +{ + nitf_Uint8 p8[2] = /* For big-endian test */ + { + 1, 2 + }; + nitf_Uint16 *p16; /* For big-endian test */ + + p16 = (nitf_Uint16 *) p8; + /* 0x102 => big-endian */ + return ((*p16 == 0x102) ? 1 : 0); +} + +NITFPRIV(int) nitf_ImageIO_checkSubWindow(_nitf_ImageIO * nitf, + nitf_SubWindow * subWindow, + int *all, nitf_Error * error) +{ + nitf_Uint32 rowSkip; /* Row skip factor */ + nitf_Uint32 colSkip; /* Column skip factor */ + nitf_Uint32 bandIdx; /* Current band index */ + nitf_Uint32 numRowsFR; /* Number of rows at full resolution */ + nitf_Uint32 numColsFR; /* Number of columns at full resolution */ + + if (subWindow->downsampler != NULL) + { + rowSkip = subWindow->downsampler->rowSkip; + colSkip = subWindow->downsampler->colSkip; + } + else + { + rowSkip = 1; + colSkip = 1; + } + + /* Look for down-sampling */ + + if ((rowSkip > nitf->blockInfo.numRowsPerBlock) + || (colSkip > nitf->blockInfo.numColsPerBlock)) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_READING_FROM_FILE, + "Invalid pixel skips %ld %ld (limits are %ld %ld)", + rowSkip, colSkip, + nitf->blockInfo.numRowsPerBlock, + nitf->blockInfo.numColsPerBlock); + return NITF_FAILURE; + } + + numRowsFR = (subWindow->numRows) * rowSkip; + numColsFR = (subWindow->numCols) * colSkip; + + /* Check sub-window size */ + + if (numRowsFR > (nitf->numRows + rowSkip - 1) || numRowsFR == 0) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_READING_FROM_FILE, + "Invalid number of rows %ld (Full resolution) (limit is %ld)", + numRowsFR, nitf->numRows); + return NITF_FAILURE; + } + + if (numColsFR > (nitf->numColumns + colSkip - 1) || numColsFR == 0) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_READING_FROM_FILE, + "Invalid number of columns %ld (Full resolution) (limit is %ld)", + numColsFR, nitf->numColumns); + return NITF_FAILURE; + } + + /* Check sub-window position */ + + if (subWindow->startRow + numRowsFR > (nitf->numRows + rowSkip - 1)) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_READING_FROM_FILE, + "Invalid start row %ld for sub-window height %ld rows," + "full resolution (limit is %ld)", + subWindow->startRow, numRowsFR, nitf->numRows - 1); + return NITF_FAILURE; + } + + if (subWindow->startCol + numColsFR > (nitf->numColumns + colSkip - 1)) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_READING_FROM_FILE, + "Invalid start column %ld for sub-window width %ld columns," + "full resolution (limit is %ld)", + subWindow->startCol, numColsFR, + nitf->numColumns - 1); + return NITF_FAILURE; + } + + /* Check requested bands */ + + if (subWindow->numBands > nitf->numBands) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_READING_FROM_FILE, + "Too many bands %ld (limit is %ld)\n", + subWindow->numBands, nitf->numBands); + return NITF_FAILURE; + } + + if (subWindow->numBands <= 0) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_READING_FROM_FILE, + "Invalid bands count %ld\n", subWindow->numBands, + nitf->numBands); + return NITF_FAILURE; + } + + for (bandIdx = 0; bandIdx < subWindow->numBands; bandIdx++) + { + if (subWindow->bandList[bandIdx] >= nitf->numBands) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_READING_FROM_FILE, + "Invalid band %ld (limit is %ld)\n", + subWindow->bandList[bandIdx], + nitf->numBands - 1); + return NITF_FAILURE; + } + } + + /* Check for full image request */ + + *all = 0; + if ((numRowsFR == nitf->numRowsActual) + && (numColsFR == nitf->numColumnsActual)) + *all = 1; + + return NITF_SUCCESS; +} + + +NITFPRIV(NITF_BOOL) nitf_ImageIO_checkOneRead(_nitf_ImageIO * nitfI, + NITF_BOOL all) +{ + NITF_BOOL oneReadA; /* Complete request in one read flag, partial logic */ + NITF_BOOL oneReadB; /* Complete request in one read flag, partial logic */ + NITF_BOOL oneReadC; /* Complete request in one read flag, partial logic */ + NITF_BOOL oneReadRGB; + NITF_BOOL oneReadIQ; + NITF_BOOL oneRead; /* The result */ + + /* + * Look for the special case where pixel type is "B" (binary). This can + * look like a one read case, but is actually handled as a + * type of compression + */ + + if (nitfI->pixel.type == NITF_IMAGE_IO_PIXEL_TYPE_B) + return 0; + + /* + * Look for the "single read" cases. + * + * If A: + * The image has only one block + * The full image is being read + * The blocking mode is "B" + * No compression (for now) + */ + + oneReadA = ((nitfI->nBlocksPerRow * nitfI->nBlocksPerColumn) == 1) + && all + && (nitfI->blockingMode & NITF_IMAGE_IO_BLOCKING_MODE_S) + && (nitfI->compression + & (NITF_IMAGE_IO_COMPRESSION_NC | + NITF_IMAGE_IO_COMPRESSION_NM)); + /* + * Or B: + * The image has only one block per column + * The full image is being read + * The blocking mode is "S" + * No compression (for now) + */ + oneReadB = (nitfI->nBlocksPerColumn == 1) + && all + && (nitfI->blockingMode & NITF_IMAGE_IO_BLOCKING_MODE_S) + && (nitfI->compression + & (NITF_IMAGE_IO_COMPRESSION_NC | + NITF_IMAGE_IO_COMPRESSION_NM)); + /* + * Or C: + * The image has only one band + * The image has only one block per column + * The full image is being read + * The blocking mode is "B" + * No compression (for now) + */ + oneReadC = (nitfI->numBands == 1) + && (nitfI->nBlocksPerColumn == 1) + && all + && (nitfI->blockingMode & NITF_IMAGE_IO_BLOCKING_MODE_B) + && (nitfI->compression + & (NITF_IMAGE_IO_COMPRESSION_NC | + NITF_IMAGE_IO_COMPRESSION_NM)); + + oneReadRGB = (nitfI->blockingMode == NITF_IMAGE_IO_BLOCKING_MODE_RGB24) + && (nitfI->nBlocksPerColumn == 1) && all; + + oneReadIQ = (nitfI->blockingMode == NITF_IMAGE_IO_BLOCKING_MODE_IQ) + && (nitfI->nBlocksPerColumn == 1) && all; + + + /* Actually, its one read per band */ + oneRead = oneReadA || oneReadB || oneReadC || oneReadRGB || oneReadIQ; + + return oneRead; +} + + +NITFPRIV(int) nitf_ImageIO_mkMasks(nitf_ImageIO * img, + nitf_IOInterface* io, int reading, + nitf_Error * error) +{ + _nitf_ImageIO *nitf; /* Parent _nitf_ImageIO structure */ + nitf_Uint32 nBlocksTotal; /* Total number of blocks */ + nitf_Uint32 maskSizeMemory; /* Block mask size in bytes in memory */ + nitf_Uint32 maskSizeFile; /* Block mask size in bytes in the file */ + nitf_Uint64 maskOffset; /* Current mask offset */ + nitf_Uint64 *maskp; /* Current mask entry */ + size_t bytesPerBlock; /* Total bytes in one block */ + nitf_Uint32 headerOffset; /* File offset of masks due to mask header */ + nitf_Uint32 padOffset; /* File offset of pad mask due to block mask */ + nitf_Uint32 i; + + nitf = (_nitf_ImageIO *) img; + + nBlocksTotal = nitf->nBlocksTotal; + bytesPerBlock = nitf->blockSize; /* Adjust for B and 12 bit pixels */ + + if(nitf->pixel.type == NITF_IMAGE_IO_PIXEL_TYPE_B) + { + bytesPerBlock = (nitf->blockSize + 7) / 8; + } + + if(nitf->pixel.type == NITF_IMAGE_IO_PIXEL_TYPE_12) + { + bytesPerBlock = 3*((nitf->blockSize/2)/nitf->pixel.bytes); + if((nitf->blockSize/nitf->pixel.bytes) & 1) /* Odd number of pixels */ + bytesPerBlock += 2; + } + + /* Initialize header */ + + if (!nitf_ImageIO_initMaskHeader + (nitf, io, nBlocksTotal, reading, error)) + return NITF_FAILURE; + + /* Adjust image pixel offset */ + + nitf->pixelBase += nitf->maskHeader.imageDataOffset; + + /* Allocate Block mask */ + + maskSizeFile = nBlocksTotal * sizeof(nitf_Uint32); + maskSizeMemory = (nBlocksTotal + 1) * sizeof(nitf_Uint64); + nitf->blockMask = (nitf_Uint64 *) NITF_MALLOC(maskSizeMemory); + + if (nitf->blockMask == NULL) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_MEMORY, + "Memory allocation error: %s", NITF_STRERROR(NITF_ERRNO)); + return NITF_FAILURE; + } + + if ((nitf->maskHeader.blockRecordLength == 0) || !reading) + { /* No mask */ + headerOffset = 0; + maskOffset = 0; + + maskp = nitf->blockMask; + for (i = 0; i < nBlocksTotal + 1; i++) + { + *(maskp++) = maskOffset; + maskOffset += bytesPerBlock; + } + padOffset = 0; + } + else + { + /* + * Because the in memory offset is 64-bit and the file is 32-bit + * you must allocate a 32-bit array for read and copy after + * byte-swapping + */ + nitf_Uint32 *fileMask; /* Buffer to hold file mask */ + nitf_Uint32 i; + + fileMask = (nitf_Uint32 *) NITF_MALLOC(maskSizeFile); + if (fileMask == NULL) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_MEMORY, + "Memory allocation error: %s", + NITF_STRERROR(NITF_ERRNO)); + return NITF_FAILURE; + } + + headerOffset = NITF_IMAGE_IO_MASK_HEADER_LEN + + nitf->maskHeader.padPixelValueLength; + + if (!nitf_ImageIO_readFromFile(io, + nitf->imageBase + headerOffset, + (nitf_Uint8 *) fileMask, + maskSizeFile, error)) + { + NITF_FREE(fileMask); + return NITF_FAILURE; + } + + /* The offsets are stored as big-endian binary */ + if (!nitf_ImageIO_bigEndian()) + nitf_ImageIO_swapOnly_4((nitf_Uint8 *) fileMask, nBlocksTotal, 0); + + for (i = 0;i < nBlocksTotal;i++) + nitf->blockMask[i] = fileMask[i]; + + nitf->blockMask[nBlocksTotal] = + nitf->blockMask[nBlocksTotal - 1] + bytesPerBlock; + + padOffset = maskSizeFile; + NITF_FREE(fileMask); + } + + /* Allocate pad pixel mask */ + if (nitf->padMask != NULL) /* Should not happen */ + return NITF_SUCCESS; + + nitf->padMask = (nitf_Uint64 *) NITF_MALLOC(maskSizeMemory); + if (nitf->padMask == NULL) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_MEMORY, + "Memory allocation error: %s", + NITF_STRERROR(NITF_ERRNO)); + return NITF_FAILURE; + } + + /* + * Create masks with all blocks marked as unpadded if either there + * is not pad mask on read or this is a write operstion + */ + + if ((nitf->maskHeader.padRecordLength == 0) || !reading) + { /* No mask */ + for (i = 0;i < nBlocksTotal;i++) + nitf->padMask[i] = NITF_IMAGE_IO_NO_BLOCK; + } + else + { /* Read mask in file */ + /* + * Because the in memory offset is 64-bit and the file is 32-bit + * you must allocate a 32-bit array for read and copy after + * byte-swapping + */ + nitf_Uint32 *fileMask; /* Buffer to hold file mask */ + nitf_Uint32 i; + + fileMask = (nitf_Uint32 *) NITF_MALLOC(maskSizeFile); + if (fileMask == NULL) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_MEMORY, + "Memory allocation error: %s", + NITF_STRERROR(NITF_ERRNO)); + return NITF_FAILURE; + } + + if (!nitf_ImageIO_readFromFile(io, + nitf->imageBase + headerOffset + + padOffset, + (nitf_Uint8 *) fileMask, + maskSizeFile, error)) + { + NITF_FREE(fileMask); + return NITF_FAILURE; + } + + /* The offsets are stored as big-endian binary */ + if (nitf_ImageIO_bigEndian()) + nitf_ImageIO_swapOnly_4((nitf_Uint8 *) fileMask, nBlocksTotal, 0); + + for (i = 0; i < nBlocksTotal;i++) + nitf->padMask[i] = fileMask[i]; + + NITF_FREE(fileMask); + } + + return NITF_SUCCESS; +} + +/*========================= Pad Pixel Scan Functions ========================*/ + +NITF_IMAGE_IO_PAD_SCANNER(_nitf_Image_IO_pad_scan_1, nitf_Uint8) +NITF_IMAGE_IO_PAD_SCANNER(_nitf_Image_IO_pad_scan_2, nitf_Uint16) +NITF_IMAGE_IO_PAD_SCANNER(_nitf_Image_IO_pad_scan_4, nitf_Uint32) +NITF_IMAGE_IO_PAD_SCANNER(_nitf_Image_IO_pad_scan_8, nitf_Uint64) + +NITFPRIV(int) nitf_ImageIO_initMaskHeader(_nitf_ImageIO * nitf, + nitf_IOInterface* io, + nitf_Uint32 blockCount, + int reading, + nitf_Error * error) +{ + /* The structure to initialize */ + _nitf_ImageIO_MaskHeader *maskHeader; + + /* Holds mask header (except pad value) */ + maskHeader = &(nitf->maskHeader); + + if (maskHeader->ready) + return NITF_SUCCESS; + + if ((nitf->compression & /* Look for no mask */ + (NITF_IMAGE_IO_COMPRESSION_NM + | NITF_IMAGE_IO_COMPRESSION_M1 + | NITF_IMAGE_IO_COMPRESSION_M3 + | NITF_IMAGE_IO_COMPRESSION_M4 + | NITF_IMAGE_IO_COMPRESSION_M5 + | NITF_IMAGE_IO_COMPRESSION_M8)) == 0 /* No masks */ ) + { + maskHeader->ready = 1; + return NITF_SUCCESS; + } + + /* Create header if not reading */ + + if (!reading) + { + /* Check for masked type with S blocks (not supported) */ + if (nitf->blockingMode == NITF_IMAGE_IO_BLOCKING_MODE_S) + { + nitf_Error_init(error, + "Masked image with S mode blocking is not supported", + NITF_CTXT, NITF_ERR_INVALID_PARAMETER); + return NITF_FAILURE; + } + maskHeader->blockRecordLength = 4; + + /* + * Check for margin padding and set pad pixel length + * accordingly (Margin padding is required when image + * dimensions are not integral multiples of + * block dimensions). + */ + maskHeader->padRecordLength = 4; + maskHeader->padPixelValueLength = nitf->pixel.bytes; + + /* + * The image data offset is the base header length plus the pad pixel + * value (if present) plus the lengths of the masks (if present). + * Since this is only called for a write with a masked compression + * type (i.e., "NM") the base header is always written. + */ + + maskHeader->imageDataOffset = + NITF_IMAGE_IO_MASK_HEADER_LEN + + + maskHeader->padPixelValueLength; + + if (maskHeader->blockRecordLength != 0) + maskHeader->imageDataOffset += + blockCount * sizeof(nitf_Uint32); + + if (maskHeader->padRecordLength != 0) + maskHeader->imageDataOffset += + blockCount * sizeof(nitf_Uint32); + + /* Set the pad scanner function based on the pad pixel length */ + switch (maskHeader->padPixelValueLength) + { + case 1: + nitf->padScanner = _nitf_Image_IO_pad_scan_1; + break; + case 2: + nitf->padScanner = _nitf_Image_IO_pad_scan_2; + break; + case 4: + nitf->padScanner = _nitf_Image_IO_pad_scan_4; + break; + case 8: + nitf->padScanner = _nitf_Image_IO_pad_scan_8; + break; + default: + nitf->padScanner = NULL; + break; + } + + maskHeader->ready = 1; + return NITF_SUCCESS; + } + + /* Read header from file */ + if (!nitf_ImageIO_readMaskHeader(nitf, io, error)) + return NITF_FAILURE; + + maskHeader->ready = 1; + return NITF_SUCCESS; +} + + +NITFPRIV(int) nitf_ImageIO_readMaskHeader(_nitf_ImageIO * nitf, + nitf_IOInterface* io, + nitf_Error * error) +{ + /* The structure to initialize */ + _nitf_ImageIO_MaskHeader *maskHeader; + nitf_Uint8 buffer[NITF_IMAGE_IO_MASK_HEADER_LEN]; + nitf_Uint8 *bp; /* Points into buffer */ + + maskHeader = &(nitf->maskHeader); + + /* Read header and load it into the mask header structure */ + + if (!nitf_ImageIO_readFromFile(io, nitf->imageBase, + buffer, NITF_IMAGE_IO_MASK_HEADER_LEN, + error)) + return NITF_FAILURE; + + bp = buffer; + memcpy(&(maskHeader->imageDataOffset), bp, sizeof(nitf_Uint32)); + bp += 4; + memcpy(&(maskHeader->blockRecordLength), bp, sizeof(nitf_Uint16)); + bp += 2; + memcpy(&(maskHeader->padRecordLength), bp, sizeof(nitf_Uint16)); + bp += 2; + memcpy(&(maskHeader->padPixelValueLength), bp, sizeof(nitf_Uint16)); + + /* Byte swap structure if needed */ + + if (!nitf_ImageIO_bigEndian()) + nitf_ImageIO_swapMaskHeader(maskHeader); + + /* + The pad pixel value length is in bits and the structure field is in + bytes. Unless the field is 0 substitute the number of bytes per pixel in + the structure. NOTE: maskHeader->padPixelValueLength == 0 mean zero bits + in the pad pixel which means no pad value. + */ + + if (maskHeader->padPixelValueLength != 0) + maskHeader->padPixelValueLength = nitf->pixel.bytes; + + /* Read pad pixel value */ + + if (maskHeader->padPixelValueLength != 0) + { + if (!nitf_ImageIO_readFromFile(io, + nitf->imageBase + + NITF_IMAGE_IO_MASK_HEADER_LEN, + nitf->pixel.pad, nitf->pixel.bytes, + error)) + { + return NITF_FAILURE; + } + } + + return NITF_SUCCESS; +} + + +NITFPRIV(int) nitf_ImageIO_writeMasks(_nitf_ImageIO * nitf, + nitf_IOInterface* io, + nitf_Error * error) +{ + /* Copy of the structure to write */ + _nitf_ImageIO_MaskHeader maskHeader; + nitf_Uint8 buffer[NITF_IMAGE_IO_MASK_HEADER_LEN]; + nitf_Uint16 padCodeLength; /* Pad code length for header */ + nitf_Uint64 maskOffset; /* Offset of block or pad mask */ + nitf_Uint32 maskSizeFile; /* Block mask size in bytes in the file */ + + /* Do not write anything if the IC is not a mask type */ + + if ((nitf->compression & + (NITF_IMAGE_IO_COMPRESSION_NM + | NITF_IMAGE_IO_COMPRESSION_M1 + | NITF_IMAGE_IO_COMPRESSION_M3 + | NITF_IMAGE_IO_COMPRESSION_M4 + | NITF_IMAGE_IO_COMPRESSION_M5 + | NITF_IMAGE_IO_COMPRESSION_M8)) == 0 /* No masks */ ) + return NITF_SUCCESS; + + /* A copy of the structure is made so it can be byte swapped if needed */ + + maskHeader = nitf->maskHeader; + if (!nitf_ImageIO_bigEndian()) + nitf_ImageIO_swapMaskHeader(&maskHeader); + + /* Format and write the header buffer */ + + buffer[0] = ((nitf_Uint8 *) & maskHeader.imageDataOffset)[0]; + buffer[1] = ((nitf_Uint8 *) & maskHeader.imageDataOffset)[1]; + buffer[2] = ((nitf_Uint8 *) & maskHeader.imageDataOffset)[2]; + buffer[3] = ((nitf_Uint8 *) & maskHeader.imageDataOffset)[3]; + + buffer[4] = ((nitf_Uint8 *) & maskHeader.blockRecordLength)[0]; + buffer[5] = ((nitf_Uint8 *) & maskHeader.blockRecordLength)[1]; + buffer[6] = ((nitf_Uint8 *) & maskHeader.padRecordLength)[0]; + buffer[7] = ((nitf_Uint8 *) & maskHeader.padRecordLength)[1]; + + /* + Write pad output pixel code length actually NBPP, M3 is a special case + fix later XXX + */ + + if (nitf->maskHeader.padPixelValueLength != 0) + padCodeLength = 8 * (nitf->pixel.bytes); + else + padCodeLength = 0; + + if (nitf_ImageIO_bigEndian()) + { + ((nitf_Uint8 *) buffer)[8] = padCodeLength >> 8; + ((nitf_Uint8 *) buffer)[9] = padCodeLength & 0xff; + } + else + { + ((nitf_Uint8 *) buffer)[9] = padCodeLength >> 8; + ((nitf_Uint8 *) buffer)[8] = padCodeLength & 0xff; + } + + if (!nitf_ImageIO_writeToFile(io, nitf->imageBase, + buffer, NITF_IMAGE_IO_MASK_HEADER_LEN, + error)) + return NITF_FAILURE; + + /* Write pad pixel value */ + + maskOffset = nitf->imageBase + NITF_IMAGE_IO_MASK_HEADER_LEN; + if (maskHeader.padPixelValueLength != 0) + { + if (!nitf_ImageIO_writeToFile(io, maskOffset, + nitf->pixel.pad, + (size_t)nitf->maskHeader.padPixelValueLength, + error)) + { + return NITF_FAILURE; + } + maskOffset += nitf->maskHeader.padPixelValueLength; + } + + /* + Write the block mask. The offsets are stored as big-endian binary so + swap them on little endian machines. swap in place and swap back after write + */ + + if (nitf->maskHeader.blockRecordLength != 0) + { + /* + Because the in memory offset is 64-bit and the file is 32-bit + you must allocate a 32-bit array and byte-swap after copying + */ + nitf_Uint32 *fileMask; /* Buffer to hold file mask */ + nitf_Uint32 i; + + maskSizeFile = nitf->nBlocksTotal * sizeof(nitf_Uint32); + fileMask = (nitf_Uint32 *) NITF_MALLOC(maskSizeFile); + if (fileMask == NULL) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_MEMORY, + "Memory allocation error: %s", NITF_STRERROR(NITF_ERRNO)); + return NITF_FAILURE; + } + + for (i = 0;i < nitf->nBlocksTotal;i++) + fileMask[i] = nitf->blockMask[i]; + + for (i = 0;i < nitf->nBlocksTotal;i++) /* Overflow check */ + if (fileMask[i] != nitf->blockMask[i]) + { + NITF_FREE(fileMask); + nitf_Error_initf(error, NITF_CTXT, + NITF_ERR_INVALID_PARAMETER, "Mask index overflow"); + return NITF_FAILURE; + } + + if (!nitf_ImageIO_bigEndian()) + nitf_ImageIO_swapOnly_4((nitf_Uint8 *) fileMask, + nitf->nBlocksTotal, 0); + + if (!nitf_ImageIO_writeToFile(io, maskOffset, + (nitf_Uint8 *) fileMask, + (size_t)nitf->nBlocksTotal * + sizeof(nitf_Uint32), error)) + { + NITF_FREE(fileMask); + return NITF_FAILURE; + } + + maskOffset += nitf->nBlocksTotal * sizeof(nitf_Uint32); + NITF_FREE(fileMask); + } + /* + Write the pad mask. + */ + + if (nitf->maskHeader.padRecordLength != 0) + { + /* + Because the in memory offset is 64-bit and the file is 32-bit + you must allocate a 32-bit array and byte-swap after copying + */ + nitf_Uint32 *fileMask; /* Buffer to hold file mask */ + nitf_Uint32 i; + + maskSizeFile = nitf->nBlocksTotal * sizeof(nitf_Uint32); + fileMask = (nitf_Uint32 *) NITF_MALLOC(maskSizeFile); + if (fileMask == NULL) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_MEMORY, + "Memory allocation error: %s", NITF_STRERROR(NITF_ERRNO)); + return NITF_FAILURE; + } + + for (i = 0;i < nitf->nBlocksTotal;i++) + fileMask[i] = nitf->padMask[i]; + + for (i = 0;i < nitf->nBlocksTotal;i++) /* Overflow check */ + if (fileMask[i] != nitf->padMask[i]) + { + NITF_FREE(fileMask); + nitf_Error_initf(error, NITF_CTXT, + NITF_ERR_INVALID_PARAMETER, "Mask index overflow"); + return NITF_FAILURE; + } + + if (!nitf_ImageIO_bigEndian()) + nitf_ImageIO_swapOnly_4((nitf_Uint8 *) fileMask, + nitf->nBlocksTotal, 0); + + if (!nitf_ImageIO_writeToFile(io, maskOffset, + (nitf_Uint8 *) fileMask, + (size_t)nitf->nBlocksTotal * + sizeof(nitf_Uint32), error)) + { + NITF_FREE(fileMask); + return NITF_FAILURE; + } + + NITF_FREE(fileMask); + maskOffset += nitf->nBlocksTotal * sizeof(nitf_Uint32); + } + return NITF_SUCCESS; +} + + +NITFPRIV(void) nitf_ImageIO_swapMaskHeader(_nitf_ImageIO_MaskHeader * + header) +{ + nitf_Uint8 *hp; /* Points into header */ + nitf_Uint8 tmp; /* Temp value for byte swaps */ + + hp = (nitf_Uint8 *) & (header->imageDataOffset); + tmp = hp[0]; + hp[0] = hp[3]; + hp[3] = tmp; + tmp = hp[1]; + hp[1] = hp[2]; + hp[2] = tmp; + + hp = (nitf_Uint8 *) & (header->blockRecordLength); + tmp = hp[0]; + hp[0] = hp[1]; + hp[1] = tmp; + + hp = (nitf_Uint8 *) & (header->padRecordLength); + tmp = hp[0]; + hp[0] = hp[1]; + hp[1] = tmp; + + hp = (nitf_Uint8 *) & (header->padPixelValueLength); + tmp = hp[0]; + hp[0] = hp[1]; + hp[1] = tmp; + + return; +} + + +NITFPRIV(int) nitf_ImageIO_oneRead(_nitf_ImageIOControl * cntl, + nitf_IOInterface* io, + nitf_Error * error) +{ + _nitf_ImageIO *nitf; /* Parent _nitf_ImageIO object */ + _nitf_ImageIOBlock *blockIO; /* The current block IO structure */ + size_t pixelCount; /* Total pixel count (size of one band in pixels) */ + size_t count; /* Total read count (size of one band in bytes) */ + + nitf = cntl->nitf; + blockIO = &(cntl->blockIO[0][0]); + pixelCount = (size_t)nitf->numRowsActual * (size_t)nitf->numColumnsActual; + count = pixelCount * nitf->pixel.bytes; + + if (!nitf_ImageIO_readFromFile(io, + blockIO->cntl->nitf->pixelBase + + blockIO->blockOffset.orig, + blockIO->user.buffer + + blockIO->user.offset.mark, + count,error)) + return NITF_FAILURE; + + if (nitf->vtbl.unformat != NULL) + (*(nitf->vtbl.unformat)) (blockIO->user.buffer + + blockIO->user.offset.mark, + pixelCount, nitf->pixel.shift); + + return NITF_SUCCESS; +} + + +/* This function is used when FR == DR (no down-Sampling) */ + +NITFPRIV(int) nitf_ImageIO_readRequest(_nitf_ImageIOControl * cntl, + nitf_IOInterface* io, + nitf_Error * error) +{ + _nitf_ImageIO *nitf; /* Parent _nitf_ImageIO object */ + nitf_Uint32 nBlockCols; /* Number of block columns */ + nitf_Uint32 numRows; /* Number of rows in the requested sub-window */ + nitf_Uint32 numBands; /* Number of bands */ + nitf_Uint32 col; /* Block column index */ + nitf_Uint32 row; /* Current row in sub-window */ + nitf_Uint32 band; /* Current band in sub-window */ + _nitf_ImageIOBlock *blockIO; /* The current block IO structure */ + + nitf = cntl->nitf; + numRows = cntl->numRows; + numBands = cntl->numBandSubset; + nBlockCols = cntl->nBlockIO / numBands; + + for (col = 0; col < nBlockCols; col++) + { + for (row = 0; row < numRows; row++) + { + for (band = 0; band < numBands; band++) + { + blockIO = &(cntl->blockIO[col][band]); + if (blockIO->doIO) + if (!(*(nitf->vtbl.reader)) (blockIO, io, error)) + return NITF_FAILURE; + + if (nitf->vtbl.unpack != NULL) + (*(nitf->vtbl.unpack)) (blockIO, error); + + if (nitf->vtbl.unformat != NULL) + (*(nitf->vtbl.unformat)) (blockIO->user.buffer + + blockIO->user.offset.mark, + blockIO->pixelCountDR, + nitf->pixel.shift); + /* + * You have to check for last row and not call + * nitf_ImageIO_nextRow because if the last row is the + * last line in the last block, you can + * wind up accessing past the end of the block mask + * while setting-up for + * the non-existant next block. + */ + if (row != numRows - 1) + nitf_ImageIO_nextRow(blockIO, 0); + + if (blockIO->rowsUntil == 0) + /* + * See documentation of nitf_ImageIOBlock for an + * explaination of the - 1 + */ + blockIO->rowsUntil = nitf->numRowsPerBlock - 1; + else + blockIO->rowsUntil -= 1; + } + } + } + + return 1; +} + +/* This function is used when FR != DR (down-Sampling) */ +NITFPRIV(int) nitf_ImageIO_readRequestDownSample(_nitf_ImageIOControl * + cntl, + nitf_SubWindow * + subWindow, + nitf_IOInterface* io, + nitf_Error * error) +{ + _nitf_ImageIO *nitf; /* Parent _nitf_ImageIO object */ + nitf_Uint32 nBlockCols; /* Number of block columns */ + nitf_Uint32 numRowsFull; /* Number of rows to read in full res sub-window */ + nitf_Uint32 numBands; /* Number of bands */ + nitf_Uint32 col; /* Block column index */ + nitf_Uint32 row; /* Current row in sub-window */ + nitf_Uint32 band; /* Current band in sub-window */ + _nitf_ImageIOBlock *blockIO; /* The current block IO structure */ + nitf_Uint8 *columnSave; /* Column save buffer ptr,current block column */ + NITF_BOOL noUserInc; /* Do not increment user buffer pointer if TRUE */ + nitf_Uint32 bytes; /* Pixel size in bytes */ + nitf_Uint32 rowSkipCount; /* Number of rows since the last row skip */ + nitf_Uint32 numColsDR; /* Number of columns, down-sample resolution */ + + nitf = cntl->nitf; + + /* + * Calculate the number of rows to read (full resolution). Check for the + * full resolution size to go outside of the image (This can happen if + * down-sampling and the final row of neighbords is partially out of the + * image + */ + + numRowsFull = (cntl->numRows) * (cntl->rowSkip); + if (cntl->row + numRowsFull > nitf->numRows) + numRowsFull = nitf->numRows - cntl->row; + + numBands = cntl->numBandSubset; + nBlockCols = cntl->nBlockIO / numBands; + bytes = nitf->pixel.bytes; + noUserInc = 1; /* Only increment after calling down-sample plugin */ + rowSkipCount = 0; + + blockIO = NULL; /* Avoid spurious uninitialized warning */ + numColsDR = 0; /* Avoid spurious uninitialized warning */ + for (col = 0; col < nBlockCols; col++) + { + columnSave = cntl->columnSave; + rowSkipCount = 0; + for (row = 0; row < numRowsFull; row++) + { + for (band = 0; band < numBands; band++) + { + blockIO = &(cntl->blockIO[col][band]); + numColsDR = blockIO->pixelCountDR; + + if (blockIO->doIO) + if (!(*(nitf->vtbl.reader)) (blockIO, io, error)) + return NITF_FAILURE; + + if (nitf->vtbl.unpack != NULL) + (*(nitf->vtbl.unpack)) (blockIO, error); + + /* + * Copy first neighborhood data from previous block + * column and save + * residual data from this column + */ + + if (blockIO->residual != 0) + memmove(blockIO->unpacked.buffer + + blockIO->unpacked.offset.mark - + (blockIO->residual) * bytes, columnSave, + (blockIO->residual) * bytes); + + if (blockIO->myResidual != 0) + { + /* Normal case (not last block) */ + if (col != (nBlockCols - 1)) + { + memmove(columnSave, + blockIO->unpacked.buffer + + blockIO->unpacked.offset.mark + + (blockIO->pixelCountFR - + blockIO->myResidual) * bytes, + (blockIO->myResidual) * bytes); + } + else /* Off the side of the image, supply pad */ + { + if (cntl->padBuffer == NULL) + if (!nitf_ImageIO_allocatePad(cntl, error)) + return NITF_FAILURE; + + memmove(blockIO->unpacked.buffer + + blockIO->unpacked.offset.mark + + blockIO->pixelCountFR * bytes, + cntl->padBuffer, + (blockIO->myResidual) * bytes); + } + } + + /* Update columnSave, array is organized like [row][band] */ + + columnSave += (cntl->columnSkip) * bytes; + + if (nitf->vtbl.unformat != NULL) + (*(nitf->vtbl.unformat)) (blockIO->unpacked.buffer + + (rowSkipCount) * + (nitf->numColumnsPerBlock + + cntl->columnSkip) * bytes, + blockIO->formatCount, + nitf->pixel.shift); + + /* + * Setup down-sample plugin buffer arguments + * if there is a complete sample + * window of rows. + */ + + if (rowSkipCount == (cntl->rowSkip - 1)) + { + blockIO->rwBuffer.offset.mark = + blockIO->rwBuffer.offset.orig - cntl->bufferInc; + blockIO->unpacked.offset.mark = + blockIO->unpacked.offset.orig - cntl->unpackedInc; + cntl->downSampleIn[band] = + (NITF_DATA *) (blockIO->unpacked.buffer); + cntl->downSampleOut[band] = + (NITF_DATA *) (blockIO->user.buffer + + blockIO->user.offset.mark); + noUserInc = 0; /* Increment user buffer this row */ + } + + /* + * You have to check for last row and not + * call nitf_ImageIO_nextRow + * because if the last row is the last line in + * the last block, you can + * wind up accessing past the end of the block mask + * while setting-up for + * the non-existant next block. + */ + if (row != numRowsFull - 1) + nitf_ImageIO_nextRow(blockIO, noUserInc); + noUserInc = 1; + + if (blockIO->rowsUntil == 0) + /* + * See documentation of nitf_ImageIOBlock + * for an explaination of the - 1 + */ + blockIO->rowsUntil = nitf->numRowsPerBlock - 1; + else + blockIO->rowsUntil -= 1; + } + + if (rowSkipCount == (cntl->rowSkip - 1)) + { + /* For down-sampler call */ + nitf_Uint32 colsInLastWindow; + + /* Partial neighborhoods happen in last block */ + if (col == (nBlockCols - 1)) + colsInLastWindow = + cntl->columnSkip - blockIO->myResidual; + else + colsInLastWindow = cntl->columnSkip; + + /* Always one row of windows */ + if (!nitf_DownSampler_apply + (subWindow->downsampler, cntl->downSampleIn, + cntl->downSampleOut, cntl->numBandSubset, 1, numColsDR, + nitf->numColumnsPerBlock + cntl->columnSkip, + subWindow->numCols, nitf->pixel.type, + nitf->pixel.bytes, cntl->rowSkip, colsInLastWindow, + error)) + return NITF_FAILURE; + } + + rowSkipCount += 1; + if (rowSkipCount >= cntl->rowSkip) + rowSkipCount = 0; + } + + /* + * Check for a partial sampling neighborhood, if the row skip count is + * not exactly zero. This count is set to zero after a window of rows is + * passed to the down-sample plugin. If it is not zero then the + * read buffer will contain the skip count number of valid rows. + * Fill the missing rows with + * pad and call the down-sample plugin. + */ + + if (rowSkipCount != 0) + { + nitf_Uint32 padRows; /* Number of pad rows */ + /* For down-sampler call */ + nitf_Uint32 colsInLastWindow; + nitf_Uint32 i; + + if (cntl->padBuffer == NULL) + if (!nitf_ImageIO_allocatePad(cntl, error)) + return NITF_FAILURE; + /* Eliminates suprious uninitialized variable warning */ + colsInLastWindow = 0; + padRows = cntl->rowSkip - rowSkipCount; + /* Back-up blockIO pointer */ + blockIO = blockIO - numBands + 1; + for (band = 0; band < numBands; band++) + { + for (i = 0; i < padRows; i++) + { + memmove(blockIO->unpacked.buffer + + (cntl->unpackedInc) * (rowSkipCount + i), + cntl->padBuffer, cntl->unpackedInc); + } + /* Partial neighborhoods happen in last block */ + if (col == (nBlockCols - 1)) + colsInLastWindow = + cntl->columnSkip - blockIO->myResidual; + else + colsInLastWindow = cntl->columnSkip; + + /* + * The iputput pointer needs to be updated. + * This pointer is the user + * buffer plus offset. The offset is updated in the + * nextRow function, but + * only at the end of a complete sample neighborhood of rows + */ + cntl->downSampleIn[band] = + (NITF_DATA *) (blockIO->unpacked.buffer); + cntl->downSampleOut[band] = + (NITF_DATA *) (blockIO->user.buffer + + blockIO->user.offset.mark); + blockIO += 1; + } + + /* Always one row of windows */ + if (!nitf_DownSampler_apply + (subWindow->downsampler, cntl->downSampleIn, + cntl->downSampleOut, cntl->numBandSubset, 1, numColsDR, + nitf->numColumnsPerBlock + cntl->columnSkip, + subWindow->numCols, nitf->pixel.type, nitf->pixel.bytes, + rowSkipCount, colsInLastWindow, error)) + return NITF_FAILURE; + } + } + + return NITF_SUCCESS; +} + +NITFPRIV(int) nitf_ImageIO_allocatePad(_nitf_ImageIOControl * cntl, + nitf_Error * error) +{ + _nitf_ImageIO *nitf; /* NITF block structure */ + nitf_Uint8 *padBufp1; /* Pad buffer pointer 1 */ + nitf_Uint8 *padBufp2; /* Pad buffer pointer 2 */ + nitf_Uint32 i; + + nitf = cntl->nitf; + + cntl->padBuffer = (nitf_Uint8 *) NITF_MALLOC(cntl->padBufferSize); + if (cntl->padBuffer == NULL) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_MEMORY, + "Memory allocation error: %s", + NITF_STRERROR(NITF_ERRNO)); + return NITF_FAILURE; + } + memmove(cntl->padBuffer, nitf->pixel.pad, nitf->pixel.bytes); + + /* Duplicate pad pixel by propagating */ + + padBufp1 = cntl->padBuffer; + padBufp2 = cntl->padBuffer + nitf->pixel.bytes; + for (i = 0; i < cntl->padBufferSize - nitf->pixel.bytes; i++) + *(padBufp2++) = *(padBufp1++); + + return NITF_SUCCESS; +} + + +NITFPRIV(int) nitf_ImageIO_readPad(_nitf_ImageIOBlock * blockIO, + nitf_Error * error) +{ + _nitf_ImageIOControl *cntl; /* Control structure */ + + cntl = blockIO->cntl; + if (cntl->padBuffer == NULL) + if (!nitf_ImageIO_allocatePad(cntl, error)) + return NITF_FAILURE; + + memmove(blockIO->rwBuffer.buffer + blockIO->rwBuffer.offset.mark, + cntl->padBuffer,blockIO->readCount); + return NITF_SUCCESS; +} + + +NITFPRIV(int) nitf_ImageIO_readFromFile(nitf_IOInterface* io, + nitf_Uint64 fileOffset, + nitf_Uint8 * buffer, + size_t count, + nitf_Error * error) +{ + size_t bytes; /* Amount of current read */ + char *bufp; /* pointer into the buffer */ + /* Seek to the offset */ + bytes = count; + bufp = (char *) buffer; + + if (!NITF_IO_SUCCESS(nitf_IOInterface_seek(io, + (nitf_Off) fileOffset, + NITF_SEEK_SET, error))) + { + return NITF_FAILURE; + } + if (!nitf_IOInterface_read(io, bufp, bytes, error)) + { + return NITF_FAILURE; + } + return NITF_SUCCESS; +} + +NITFPRIV(int) nitf_ImageIO_writeToFile(nitf_IOInterface* io, + nitf_Uint64 fileOffset, + const nitf_Uint8 * buffer, + size_t count, + nitf_Error * error) +{ + + /* Seek to the offset */ + if (!NITF_IO_SUCCESS + (nitf_IOInterface_seek + (io, (nitf_Off) fileOffset, NITF_SEEK_SET, error))) + return NITF_FAILURE; + + /* Write the data */ + if (! nitf_IOInterface_write(io, (char *) buffer, count, error) ) + return NITF_FAILURE; + + return NITF_SUCCESS; +} + + +NITFPRIV(int) nitf_ImageIO_writeToBlock(_nitf_ImageIOBlock * blockIO, + nitf_IOInterface* io, + size_t blockOffset, + const nitf_Uint8 * buffer, + size_t count, + nitf_Error * error) +{ + _nitf_ImageIO *nitf; /* Associated image I/O object */ + /* Associated block control */ + _nitf_ImageIOBlockCacheControl *blockCntl; + nitf_Uint64 fileOffset; /* Offset in filw for write */ + /* Pad scanning function */ + _NITF_IMAGE_IO_PAD_SCAN_FUNC scanner; + + nitf = ((_nitf_ImageIOControl *) (blockIO->cntl))->nitf; + blockCntl = &(blockIO->blockControl); + scanner = nitf->padScanner; + + + if (blockCntl->block == NULL) + { + blockCntl->block = + (nitf_Uint8 *) NITF_MALLOC(nitf->blockSize); + if (blockCntl->block == NULL) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_MEMORY, + "Error allocating block buffer: %s", + NITF_STRERROR(NITF_ERRNO)); + return NITF_FAILURE; + } + } + + /* Overflow check*/ + + if ((blockOffset + count) > nitf->blockSize) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_MEMORY, + "Block buffer overflow"); + return NITF_FAILURE; + } + + /* Copy data */ + + memcpy(blockCntl->block + blockOffset, buffer, count); + + /* Write block if full */ + + if ((blockOffset + count) >= nitf->blockSize) + { + NITF_BOOL padPresent = 0; /* Pad values in block */ + NITF_BOOL dataPresent = 1; /* Data values in block */ + + /* Scan for pad if the scanner function is not NULL */ + + if (scanner != NULL) + { + (*scanner)(blockIO, &padPresent, &dataPresent); + if (!dataPresent) /* Pad only do not write */ + { + /* + * Copy down all of the offsets since with the missing block + * this gives the correct offset for the following blocks. Copy + * one less offset than the remaining blocks. The block count is + * gotten by multiplying blocks per row by blocks + * per column except + * for (band sequential) which has seperate + * masks for each band and + * is not currently supported as explained in this functions + * documentation. + * + * The pad mask is set to the no block value correct + * for a missing block + */ + /* + * This commented out code will generate the correct + * blocking mask + * for S mode but the writing of the may be at the wrong offset + * It is left here for a future update to include S mode + */ +#if 0 + if (nitf->blockingMode == NITF_IMAGE_IO_BLOCKING_MODE_S) + { + + nitf_Uint32 nBlocksPerBand; /* Number of blocks per band */ + nitf_Uint32 nBlocksTotal; /* Number of blocks total */ + nitf_Uint32 numBands; /* Number of bands */ + nitf_Uint32 fullNumber; /* Block number if full mask */ + nitf_Uint32 srcIdx; /* Index of copy source */ + nitf_Uint32 dstIdx; /* Index of copy destination */ + + nBlocksPerBand = (nitf->nBlocksPerRow) * (nitf->nBlocksPerColumn); + nBlocksTotal = nitf->nBlocksTotal; + numBands = nitf->numBands; + fullNumber = blockIO->number + nBlocksPerBand * (blockIO->band); + srcIdx = nBlocksTotal - 2; + for (dstIdx = nBlocksTotal - 1;dstIdx > fullNumber;) + { + if (nitf->blockMask[dstIdx] == NITF_IMAGE_IO_NO_BLOCK) + { + dstIdx -= 1; + continue; + } + if (nitf->blockMask[srcIdx] == NITF_IMAGE_IO_NO_BLOCK) + { + srcIdx -= 1; + continue; + } + + nitf->blockMask[dstIdx--] = nitf->blockMask[srcIdx--]; + } + } + else + memmove(&(blockIO->blockMask[blockIO->number+1]), + &(blockIO->blockMask[blockIO->number]), + (nitf->nBlocksPerRow * nitf->nBlocksPerColumn - + blockIO->number) * sizeof(nitf_Uint64)); +#endif + memmove(&(blockIO->blockMask[blockIO->number+1]), + &(blockIO->blockMask[blockIO->number]), + (nitf->nBlocksPerRow * nitf->nBlocksPerColumn - + blockIO->number) * sizeof(nitf_Uint64)); + + blockIO->blockMask[blockIO->number] = NITF_IMAGE_IO_NO_BLOCK; + blockIO->padMask[blockIO->number] = NITF_IMAGE_IO_NO_BLOCK; + return NITF_SUCCESS; /* Don't write */ + } + + if (padPresent) /* Real block with pad */ + blockIO->padMask[blockIO->number] = + blockIO->blockMask[blockIO->number]; + } + + /* + * Reset the image data offset since it may be different now + * due to skipped blocks + */ + blockIO->imageDataOffset = blockIO->blockMask[blockIO->number]; + + fileOffset = nitf->pixelBase + blockIO->imageDataOffset; + + + /* Check for compression */ + + if(nitf->compressor != NULL) + { + if(!(*(nitf->compressor->writeBlock))(nitf->compressionControl, + io,blockCntl->block,padPresent,!dataPresent,error)) + return(NITF_FAILURE); + } + else + { + /* Seek to the offset */ + if (!NITF_IO_SUCCESS + (nitf_IOInterface_seek + (io, (nitf_Off) fileOffset, NITF_SEEK_SET, error))) + return NITF_FAILURE; + + /* Write the data */ + + if (!nitf_IOInterface_write(io, + (char *) (blockCntl->block), + nitf->blockSize, error) ) + return NITF_FAILURE; + } + } + + return NITF_SUCCESS; +} + +NITFPRIV(void) nitf_ImageIO_nextRow(_nitf_ImageIOBlock * blockIO, + NITF_BOOL noUserInc) +{ + _nitf_ImageIOControl *cntl; /* Associated I/O control structure */ + + cntl = blockIO->cntl; + + if (blockIO->rowsUntil == 0) /* Next block */ + { + blockIO->number += cntl->numberInc; + blockIO->imageDataOffset = blockIO->blockMask[blockIO->number]; + blockIO->blockOffset.mark = blockIO->blockOffset.orig; + } + else + blockIO->blockOffset.mark += cntl->blockOffsetInc; + + blockIO->rwBuffer.offset.mark += cntl->bufferInc; + blockIO->unpacked.offset.mark += cntl->unpackedInc; + if (!noUserInc) + blockIO->user.offset.mark += cntl->userInc; + + return; +} + + +int nitf_ImageIO_uncachedReader(_nitf_ImageIOBlock * blockIO, + nitf_IOInterface* io, + nitf_Error * error) +{ + + /* Check for pad pixel read */ + if (blockIO->imageDataOffset == NITF_IMAGE_IO_NO_OFFSET) + { + if (!nitf_ImageIO_readPad(blockIO, error)) + return NITF_FAILURE; + + blockIO->cntl->padded = 1; + return NITF_SUCCESS; + } + else + { + if (!nitf_ImageIO_readFromFile(io, + blockIO->cntl->nitf->pixelBase + + blockIO->imageDataOffset + + blockIO->blockOffset.mark, + blockIO->rwBuffer.buffer + + blockIO->rwBuffer.offset.mark, + blockIO->readCount, error)) + { + return NITF_FAILURE; + } + + if (blockIO->padMask[blockIO->number] != NITF_IMAGE_IO_NO_OFFSET) + blockIO->cntl->padded = 1; + + return NITF_SUCCESS; + } +} + + +int nitf_ImageIO_cachedReader(_nitf_ImageIOBlock * blockIO, + nitf_IOInterface* io, + nitf_Error * error) +{ + _nitf_ImageIO *nitf; /* Associated ImageIO object */ + _nitf_ImageIOControl *cntl; /* Associated control object */ + nitf_Uint64 blockSize; + + cntl = blockIO->cntl; + nitf = cntl->nitf; + + /* Check for pad pixel read */ + + if (blockIO->imageDataOffset == NITF_IMAGE_IO_NO_OFFSET) + { + if (!nitf_ImageIO_readPad(blockIO, error)) + return NITF_FAILURE; + + cntl->padded = 1; + return NITF_SUCCESS; + } + else + { + if (nitf->blockControl.number != blockIO->number) + { + if ((nitf->pixel.type != NITF_IMAGE_IO_PIXEL_TYPE_B) + && (nitf->pixel.type != NITF_IMAGE_IO_PIXEL_TYPE_12) + && (nitf->compression & NITF_IMAGE_IO_NO_COMPRESSION)) + { + /* Allocate block buffer if required */ + if (nitf->blockControl.block == NULL) + { + nitf->blockControl.block = + (nitf_Uint8 *) NITF_MALLOC(nitf->blockSize); + if (nitf->blockControl.block == NULL) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_MEMORY, + "Error allocating block buffer: %s", + NITF_STRERROR(NITF_ERRNO)); + return NITF_FAILURE; + } + } + /* Read the block */ + + if (!nitf_ImageIO_readFromFile(io, + blockIO->cntl->nitf-> + pixelBase + + blockIO->imageDataOffset, + nitf->blockControl.block, + nitf->blockSize, error)) + return NITF_FAILURE; + } + else + { + /* Decompression interface structure */ + nitf_DecompressionInterface *interface; + + /* No plugin */ + if (nitf->decompressor == NULL) + { + nitf_Error_initf(error, NITF_CTXT, + NITF_ERR_DECOMPRESSION, + "No decompression plugin for compressed type"); + return NITF_FAILURE; + } + + interface = nitf->decompressor; + if (nitf->blockControl.block != NULL) + (*(interface->freeBlock)) (nitf->decompressionControl, + nitf->blockControl.block, + error); + nitf->blockControl.block = + (*(interface->readBlock)) (nitf->decompressionControl, + blockIO->number, &blockSize, error); + if (nitf->blockControl.block == NULL) + return NITF_FAILURE; + } + nitf->blockControl.number = blockIO->number; + } + + /* Get data from block */ + memcpy(blockIO->rwBuffer.buffer + blockIO->rwBuffer.offset.mark, + nitf->blockControl.block + blockIO->blockOffset.mark, + blockIO->readCount); + + if (blockIO->padMask[blockIO->number] != NITF_IMAGE_IO_NO_OFFSET) + blockIO->cntl->padded = 1; + + return NITF_SUCCESS; + } +} + +/*========================= Start Direct Block Reading ================================*/ +NITFPROT(NRT_BOOL) nitf_ImageIO_setupDirectBlockRead(nitf_ImageIO *nitf, + nitf_IOInterface *io, + nitf_Uint32 numBands, + nitf_Error *error) +{ + _nitf_ImageIO *nitfI; + nitf_BlockingInfo *blockInfo; /* For get blocking info call */ + + nitfI = (_nitf_ImageIO *) nitf; + + if ((nitfI->writeControl != NULL) || (nitfI->readControl != NULL)) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_MEMORY, + "I/O operation in progress"); + return NITF_FAILURE; + } + + /* *possibly* revert the optimized modes */ + nitf_ImageIO_revertOptimizedModes(nitfI, numBands); + + /* Create I/O control */ + + /* + * Check the request, set-up blocking first since the sub-window + * check requires the block size + */ + blockInfo = nitf_ImageIO_getBlockingInfo(nitf, io, error); + if (blockInfo == NULL) + return NITF_FAILURE; + + /* Not needed */ + nitf_BlockingInfo_destruct(&blockInfo); + + return NITF_SUCCESS; +} + +NITFPROT(nitf_Uint8*) nitf_ImageIO_readBlockDirect(nitf_ImageIO* nitf, + nitf_IOInterface* io, + nitf_Uint32 blockNumber, + nitf_Uint64* blockSize, + nitf_Error * error) +{ + _nitf_ImageIO *nitfI; /* Associated ImageIO object */ + nitf_Uint64 imageDataOffset; + + nitfI = (_nitf_ImageIO*) nitf; + imageDataOffset = nitfI->blockMask[blockNumber]; + + if (nitfI->blockControl.number != blockNumber) + { + if ((nitfI->pixel.type != NITF_IMAGE_IO_PIXEL_TYPE_B) + && (nitfI->pixel.type != NITF_IMAGE_IO_PIXEL_TYPE_12) + && (nitfI->compression & NITF_IMAGE_IO_NO_COMPRESSION)) + { + /* Allocate block buffer if required */ + if (nitfI->blockControl.block == NULL) + { + nitfI->blockControl.block = + (nitf_Uint8 *) NITF_MALLOC(nitfI->blockSize); + if (nitfI->blockControl.block == NULL) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_MEMORY, + "Error allocating block buffer: %s", + NITF_STRERROR(NITF_ERRNO)); + return NITF_FAILURE; + } + } + /* Read the block */ + + if (!nitf_ImageIO_readFromFile(io, + nitfI->pixelBase + imageDataOffset, + nitfI->blockControl.block, + nitfI->blockSize, error)) + return NITF_FAILURE; + + *blockSize = nitfI->blockSize; + } + else + { + /* Decompression interface structure */ + nitf_DecompressionInterface *interface; + + /* No plugin */ + if (nitfI->decompressor == NULL) + { + nitf_Error_initf(error, NITF_CTXT, + NITF_ERR_DECOMPRESSION, + "No decompression plugin for compressed type"); + return NITF_FAILURE; + } + + interface = nitfI->decompressor; + if (nitfI->blockControl.block != NULL) + (*(interface->freeBlock)) (nitfI->decompressionControl, + nitfI->blockControl.block, + error); + nitfI->blockControl.block = + (*(interface->readBlock)) (nitfI->decompressionControl, + blockNumber, blockSize, + error); + if (nitfI->blockControl.block == NULL) + return NITF_FAILURE; + } + nitfI->blockControl.number = blockNumber; + } + + return nitfI->blockControl.block; +} + +/*========================= End Direct Block Reading ================================*/ +/*========================= Start Direct Block Writing ================================*/ + +NITFPROT(NRT_BOOL) nitf_ImageIO_writeBlockDirect(nitf_ImageIO* object, + nitf_IOInterface* io, + const nitf_Uint8 * buffer, + nitf_Uint32 blockNumber, + nitf_Error * error) +{ + _nitf_ImageIO *nitf; /* Parent _nitf_ImageIO object */ + nitf_Uint64 fileOffset; /* Offset in filw for write */ + nitf_Uint64 imageDataOffset; + /* Internal representation */ + _nitf_ImageIOWriteControl *cntl; + /* Associated IO control object */ + _nitf_ImageIOControl *ioCntl; + + + cntl = ((_nitf_ImageIO *) object)->writeControl; + if (cntl == NULL) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_MEMORY, + "Write operation in not progress"); + return NITF_FAILURE; + } + + ioCntl = cntl->cntl; + nitf = ioCntl->nitf; + + //blockIO = &(ioCntl->blockIO[blockNumber][0]); + + { + NITF_BOOL padPresent = 0; /* Pad values in block */ + NITF_BOOL dataPresent = 1; /* Data values in block */ + + /* + * Reset the image data offset since it may be different now + * due to skipped blocks + */ + imageDataOffset = nitf->blockMask[blockNumber]; + + fileOffset = nitf->pixelBase + imageDataOffset; + + /* Check for compression */ + + if(nitf->compressor != NULL) + { + if(!(*(nitf->compressor->writeBlock))(nitf->compressionControl, + io, buffer, padPresent, !dataPresent, error)) + return(NITF_FAILURE); + } + else + { + /* Seek to the offset */ + if (!NITF_IO_SUCCESS + (nitf_IOInterface_seek + (io, (nitf_Off) fileOffset, NITF_SEEK_SET, error))) + return NITF_FAILURE; + + /* Write the data */ + + if (!nitf_IOInterface_write(io, + (char *) buffer, + nitf->blockSize, error) ) + return NITF_FAILURE; + } + + } + + return NITF_SUCCESS; +} + +/*========================= End Direct Block Writing ================================*/ + +int nitf_ImageIO_uncachedWriter(_nitf_ImageIOBlock * blockIO, + nitf_IOInterface* io, + nitf_Error * error) +{ + _nitf_ImageIOControl *cntl; /* Associated image I/O control object */ + _nitf_ImageIO *nitf; /* Associated image I/O object */ + + cntl = blockIO->cntl; + nitf = cntl->nitf; + + if (!nitf_ImageIO_writeToFile(io, + nitf->pixelBase + blockIO->imageDataOffset + + blockIO->blockOffset.mark, + blockIO->rwBuffer.buffer + + blockIO->rwBuffer.offset.mark, + blockIO->readCount, error)) + return NITF_FAILURE; + + /* Write column and row padding if required. This is fill not pad */ + + if (blockIO->padColumnCount != 0) + { + if (cntl->padBuffer == NULL) + if (!nitf_ImageIO_allocatePad(cntl, error)) + return NITF_FAILURE; + + if (!nitf_ImageIO_writeToFile(io, + nitf->pixelBase + + blockIO->imageDataOffset + + blockIO->blockOffset.mark + + blockIO->readCount, + cntl->padBuffer, + (size_t)blockIO->padColumnCount, + error)) + return NITF_FAILURE; + /* Fill not pad blockIO->padMask[blockIO->number] = blockIO->blockMask[blockIO->number]; */ + } + + if ((blockIO->padRowCount != 0) + && (blockIO->currentRow >= (nitf->numRows - 1))) + { + size_t writeCount; /* Amount to write each row */ + nitf_Uint64 offset; /* File offset for each write */ + size_t increment; /* Byte increment between writes */ + nitf_Uint32 rowIdx; /* Rwo counter */ + + if (cntl->padBuffer == NULL) + if (!nitf_ImageIO_allocatePad(cntl, error)) + return NITF_FAILURE; + + writeCount = blockIO->readCount + blockIO->padColumnCount; + increment = writeCount; + offset = nitf->pixelBase + blockIO->imageDataOffset + + blockIO->blockOffset.mark + increment; + + for (rowIdx = 0; rowIdx < blockIO->padRowCount; rowIdx++) + { + if (!nitf_ImageIO_writeToFile(io, + offset, cntl->padBuffer, + writeCount, error)) + return NITF_FAILURE; + offset += increment; + } + } + + return NITF_SUCCESS; +} + +int nitf_ImageIO_cachedWriter(_nitf_ImageIOBlock * blockIO, + nitf_IOInterface* io, + nitf_Error * error) +{ + _nitf_ImageIOControl *cntl; /* Associated image I/O control object */ + _nitf_ImageIO *nitf; /* Associated image I/O object */ + nitf_Uint32 i; + + cntl = blockIO->cntl; + nitf = cntl->nitf; + + if (!nitf_ImageIO_writeToBlock(blockIO, io, blockIO->blockOffset.mark, + blockIO->rwBuffer.buffer + + blockIO->rwBuffer.offset.mark, + blockIO->readCount, error)) + return NITF_FAILURE; + + /* Write column and row padding if required */ + + if (blockIO->padColumnCount != 0) + { + if (cntl->padBuffer == NULL) + if (!nitf_ImageIO_allocatePad(cntl, error)) + return NITF_FAILURE; + + if (!nitf_ImageIO_writeToBlock(blockIO, io, + blockIO->blockOffset.mark + + blockIO->readCount, + cntl->padBuffer, + blockIO->padColumnCount, error)) + return NITF_FAILURE; + } + + if ((blockIO->padRowCount != 0) + && (blockIO->currentRow >= (nitf->numRows - 1))) + { + size_t writeCount; /* Amount to write each row */ + size_t offset; /* Current offset into block buffer */ + + if (cntl->padBuffer == NULL) + if (!nitf_ImageIO_allocatePad(cntl, error)) + return NITF_FAILURE; + + writeCount = blockIO->readCount + blockIO->padColumnCount; + offset = writeCount; + + /* + * Because the pad buffer is only one line long, this + * has to be a loop of + * smaller writes + */ + for (i = 0;i < blockIO->padRowCount;i++) + { + if (!nitf_ImageIO_writeToBlock(blockIO, io, + blockIO->blockOffset.mark + offset, + cntl->padBuffer, writeCount, error)) + return NITF_FAILURE; + offset += writeCount; + } + } + + return NITF_SUCCESS; +} + +void nitf_ImageIO_setDefaultParameters(_nitf_ImageIO * object) +{ + + object->parameters.noCacheThreshold = 0.5; + object->parameters.clearCache = 0;; + + return; +} + + +void nitf_ImageIO_unformatExtend_1(nitf_Uint8 * buffer, + size_t count, + nitf_Uint32 shiftCount) +{ + nitf_Int8 shift; /* Shift count */ + nitf_Int8 *bp8; /* Buffer pointer, 8 bit */ + nitf_Int16 tmp8; /* Temp value, 8 bit */ + size_t i; + + shift = (nitf_Int8) shiftCount; + bp8 = (nitf_Int8 *) buffer; + for (i = 0; i < count; i++) + { + tmp8 = *bp8 << shift; + *(bp8++) = tmp8 >> shift; + } + + return; +} + + +void nitf_ImageIO_unformatExtend_2(nitf_Uint8 * buffer, + size_t count, + nitf_Uint32 shiftCount) +{ + nitf_Int16 shift; /* Shift count */ + nitf_Int16 *bp16; /* Buffer pointer, 16 bit */ + nitf_Int16 tmp16; /* Temp value, 16 bit */ + size_t i; + + shift = (nitf_Int16) shiftCount; + bp16 = (nitf_Int16 *) buffer; + for (i = 0; i < count; i++) + { + tmp16 = *bp16 << shift; + *(bp16++) = tmp16 >> shift; + } + + return; +} + + +void nitf_ImageIO_unformatExtend_4(nitf_Uint8 * buffer, + size_t count, + nitf_Uint32 shiftCount) +{ + nitf_Int32 shift; /* Shift count */ + nitf_Int32 *bp32; /* Buffer pointer, 32 bit */ + nitf_Int32 tmp32; /* Temp value, 32 bit */ + size_t i; + + shift = (nitf_Int32) shiftCount; + bp32 = (nitf_Int32 *) buffer; + for (i = 0; i < count; i++) + { + tmp32 = *bp32 << shift; + *(bp32++) = tmp32 >> shift; + } + + return; +} + + +/* Uses 64 bit types */ + +void nitf_ImageIO_unformatExtend_8(nitf_Uint8 * buffer, + size_t count, + nitf_Uint32 shiftCount) +{ + nitf_Int64 shift; /* Shift count */ + nitf_Int64 *bp64; /* Buffer pointer, 64 bit */ + nitf_Int64 tmp64; /* Temp value, 64 bit */ + size_t i; + + shift = (nitf_Int64) shiftCount; + bp64 = (nitf_Int64 *) buffer; + for (i = 0; i < count; i++) + { + tmp64 = *bp64 << shift; + *(bp64++) = tmp64 >> shift; + } + + return; +} + + +/*========================= nitf_ImageIO_unformatShift_* =====================*/ + +void nitf_ImageIO_unformatShift_1(nitf_Uint8 * buffer, + size_t count, + nitf_Uint32 shiftCount) +{ + nitf_Int8 shift; /* Shift count */ + nitf_Int8 *bp8; /* Buffer pointer, 8 bit */ + size_t i; + + shift = (nitf_Int8) shiftCount; + bp8 = (nitf_Int8 *) buffer; + for (i = 0; i < count; i++) + *(bp8++) >>= shift; + + return; +} + + +void nitf_ImageIO_unformatShift_2(nitf_Uint8 * buffer, + size_t count, + nitf_Uint32 shiftCount) +{ + nitf_Int16 shift; /* Shift count */ + nitf_Int16 *bp16; /* Buffer pointer, 16 bit */ + size_t i; + + shift = (nitf_Int16) shiftCount; + bp16 = (nitf_Int16 *) buffer; + for (i = 0; i < count; i++) + *(bp16++) >>= shift; + + return; +} + + +void nitf_ImageIO_unformatShift_4(nitf_Uint8 * buffer, + size_t count, + nitf_Uint32 shiftCount) +{ + nitf_Int32 shift; /* Shift count */ + nitf_Int32 *bp32; /* Buffer pointer, 32 bit */ + size_t i; + + shift = (nitf_Int32) shiftCount; + bp32 = (nitf_Int32 *) buffer; + for (i = 0; i < count; i++) + *(bp32++) >>= shift; + + return; +} + + +/* Uses 64 bit types */ + +void nitf_ImageIO_unformatShift_8(nitf_Uint8 * buffer, + size_t count, + nitf_Uint32 shiftCount) +{ + nitf_Int64 shift; /* Shift count */ + nitf_Int64 *bp64; /* Buffer pointer, 64 bit */ + size_t i; + + shift = (nitf_Int64) shiftCount; + bp64 = (nitf_Int64 *) buffer; + for (i = 0; i < count; i++) + *(bp64++) >>= shift; + + return; +} + +void nitf_ImageIO_unformatUShift_1(nitf_Uint8 * buffer, + size_t count, + nitf_Uint32 shiftCount) +{ + nitf_Uint8 shift; /* Shift count */ + nitf_Uint8 *bp8; /* Buffer pointer, 8 bit */ + size_t i; + + shift = (nitf_Uint8) shiftCount; + bp8 = (nitf_Uint8 *) buffer; + for (i = 0; i < count; i++) + *(bp8++) >>= shift; + + return; +} + + +void nitf_ImageIO_unformatUShift_2(nitf_Uint8 * buffer, + size_t count, + nitf_Uint32 shiftCount) +{ + nitf_Uint16 shift; /* Shift count */ + nitf_Uint16 *bp16; /* Buffer pointer, 16 bit */ + size_t i; + + shift = (nitf_Uint16) shiftCount; + bp16 = (nitf_Uint16 *) buffer; + for (i = 0; i < count; i++) + *(bp16++) >>= shift; + + return; +} + + +void nitf_ImageIO_unformatUShift_4(nitf_Uint8 * buffer, + size_t count, + nitf_Uint32 shiftCount) +{ + nitf_Uint32 shift; /* Shift count */ + nitf_Uint32 *bp32; /* Buffer pointer, 32 bit */ + size_t i; + + shift = (nitf_Uint32) shiftCount; + bp32 = (nitf_Uint32 *) buffer; + for (i = 0; i < count; i++) + *(bp32++) >>= shift; + + return; +} + + +/* Uses 64 bit types */ +void nitf_ImageIO_unformatUShift_8(nitf_Uint8 * buffer, + size_t count, + nitf_Uint32 shiftCount) +{ + nitf_Uint64 shift; /* Shift count */ + nitf_Uint64 *bp64; /* Buffer pointer, 64 bit */ + size_t i; + + shift = (nitf_Uint64) shiftCount; + bp64 = (nitf_Uint64 *) buffer; + for (i = 0; i < count; i++) + *(bp64++) >>= shift; + + return; +} + +void nitf_ImageIO_swapOnly_2(nitf_Uint8 * buffer, + size_t count, nitf_Uint32 shiftCount) +{ + nitf_Uint8 *bp8; /* Buffer pointer, 8 bit */ + nitf_Uint16 *bp16; /* Buffer pointer, 16 bit */ + nitf_Uint8 tmp8; /* Temp value, 8 bit */ + size_t i; + + /* Silence compiler warnings about unused variables */ + (void)shiftCount; + + bp16 = (nitf_Uint16 *) buffer; + for (i = 0; i < count; i++) + { + bp8 = (nitf_Uint8 *) bp16++; + tmp8 = bp8[0]; + bp8[0] = bp8[1]; + bp8[1] = tmp8; + } + + return; +} + + +void nitf_ImageIO_swapOnly_4(nitf_Uint8 * buffer, + size_t count, nitf_Uint32 shiftCount) +{ + nitf_Uint8 *bp8; /* Buffer pointer, 8 bit */ + nitf_Uint32 *bp32; /* Buffer pointer, 32 bit */ + nitf_Uint8 tmp8; /* Temp value, 8 bit */ + size_t i; + + /* Silence compiler warnings about unused variables */ + (void)shiftCount; + + bp32 = (nitf_Uint32 *) buffer; + for (i = 0; i < count; i++) + { + bp8 = (nitf_Uint8 *) (bp32++); + + tmp8 = bp8[0]; + bp8[0] = bp8[3]; + bp8[3] = tmp8; + tmp8 = bp8[1]; + bp8[1] = bp8[2]; + bp8[2] = tmp8; + } + + return; +} + +void nitf_ImageIO_swapOnly_4c(nitf_Uint8 * buffer, + size_t count, nitf_Uint32 shiftCount) +{ + nitf_Uint8 *bp8; /* Buffer pointer, 8 bit */ + nitf_Uint32 *bp32; /* Buffer pointer, 32 bit */ + nitf_Uint8 tmp8; /* Temp value, 8 bit */ + size_t i; + + /* Silence compiler warnings about unused variables */ + (void)shiftCount; + + bp32 = (nitf_Uint32 *) buffer; + for (i = 0; i < count; i++) + { + bp8 = (nitf_Uint8 *) (bp32++); + + tmp8 = bp8[0]; + bp8[0] = bp8[1]; + bp8[1] = tmp8; + tmp8 = bp8[2]; + bp8[2] = bp8[3]; + bp8[3] = tmp8; + } + + return; +} + + +void nitf_ImageIO_swapOnly_8(nitf_Uint8 * buffer, + size_t count, nitf_Uint32 shiftCount) +{ + nitf_Uint8 *bp8; /* Buffer pointer, 8 bit */ + nitf_Uint64 *bp64; /* Buffer pointer, 64 bit */ + nitf_Uint8 tmp8; /* Temp value, 8 bit */ + size_t i; + + /* Silence compiler warnings about unused variables */ + (void)shiftCount; + + bp64 = (nitf_Uint64 *) buffer; + for (i = 0; i < count; i++) + { + bp8 = (nitf_Uint8 *) (bp64++); + + tmp8 = bp8[0]; + bp8[0] = bp8[7]; + bp8[7] = tmp8; + tmp8 = bp8[1]; + bp8[1] = bp8[6]; + bp8[6] = tmp8; + tmp8 = bp8[2]; + bp8[2] = bp8[5]; + bp8[5] = tmp8; + tmp8 = bp8[3]; + bp8[3] = bp8[4]; + bp8[4] = tmp8; + } + + return; +} + + +void nitf_ImageIO_swapOnly_8c(nitf_Uint8 * buffer, + size_t count, nitf_Uint32 shiftCount) +{ + nitf_Uint8 *bp8; /* Buffer pointer, 8 bit */ + nitf_Uint64 *bp64; /* Buffer pointer, 64 bit */ + nitf_Uint8 tmp8; /* Temp value, 8 bit */ + size_t i; + + /* Silence compiler warnings about unused variables */ + (void)shiftCount; + + bp64 = (nitf_Uint64 *) buffer; + for (i = 0; i < count; i++) + { + bp8 = (nitf_Uint8 *) (bp64++); + + tmp8 = bp8[4]; + bp8[4] = bp8[7]; + bp8[7] = tmp8; + tmp8 = bp8[5]; + bp8[5] = bp8[6]; + bp8[6] = tmp8; + tmp8 = bp8[0]; + bp8[0] = bp8[3]; + bp8[3] = tmp8; + tmp8 = bp8[1]; + bp8[1] = bp8[2]; + bp8[2] = tmp8; + } + + return; +} + + +void nitf_ImageIO_swapOnly_16c(nitf_Uint8 * buffer, + size_t count, nitf_Uint32 shiftCount) +{ + nitf_Uint8 *bp8; /* Buffer pointer, 8 bit */ + nitf_Uint64 *bp64; /* Buffer pointer, 64 bit */ + nitf_Uint8 tmp8; /* Temp value, 8 bit */ + size_t i; + + /* Silence compiler warnings about unused variables */ + (void)shiftCount; + + bp64 = (nitf_Uint64 *) buffer; + for (i = 0; i < count; i++) + { + bp8 = (nitf_Uint8 *) (bp64++); + + tmp8 = bp8[0]; + bp8[0] = bp8[7]; + bp8[7] = tmp8; + tmp8 = bp8[1]; + bp8[1] = bp8[6]; + bp8[6] = tmp8; + tmp8 = bp8[2]; + bp8[2] = bp8[5]; + bp8[5] = tmp8; + tmp8 = bp8[3]; + bp8[3] = bp8[4]; + bp8[4] = tmp8; + + bp8 = (nitf_Uint8 *) (bp64++); + + tmp8 = bp8[0]; + bp8[0] = bp8[7]; + bp8[7] = tmp8; + tmp8 = bp8[1]; + bp8[1] = bp8[6]; + bp8[6] = tmp8; + tmp8 = bp8[2]; + bp8[2] = bp8[5]; + bp8[5] = tmp8; + tmp8 = bp8[3]; + bp8[3] = bp8[4]; + bp8[4] = tmp8; + } + + return; +} + + +void nitf_ImageIO_unformatSwapExtend_2(nitf_Uint8 * buffer, + size_t count, + nitf_Uint32 shiftCount) +{ + nitf_Int16 shift; /* Shift count */ + nitf_Uint8 *bp8; /* Buffer pointer, 8 bit */ + nitf_Int16 *bp16; /* Buffer pointer, 16 bit */ + nitf_Uint8 tmp8; /* Temp value, 8 bit */ + nitf_Uint16 tmp16; /* Temp value, 16 bit */ + size_t i; + + shift = (nitf_Int16) shiftCount; + bp16 = (nitf_Int16 *) buffer; + for (i = 0; i < count; i++) + { + bp8 = (nitf_Uint8 *) bp16; + tmp8 = bp8[0]; + bp8[0] = bp8[1]; + bp8[1] = tmp8; + + tmp16 = *bp16 << shift; + *(bp16++) = tmp16 >> shift; + } + + return; +} + + +void nitf_ImageIO_unformatSwapExtend_4(nitf_Uint8 * buffer, + size_t count, + nitf_Uint32 shiftCount) +{ + nitf_Int32 shift; /* Shift count */ + nitf_Uint8 *bp8; /* Buffer pointer, 8 bit */ + nitf_Int32 *bp32; /* Buffer pointer, 32 bit */ + nitf_Uint8 tmp8; /* Temp value, 8 bit */ + nitf_Uint8 tmp32; /* Temp value, 32 bit */ + size_t i; + + shift = (nitf_Int32) shiftCount; + bp32 = (nitf_Int32 *) buffer; + for (i = 0; i < count; i++) + { + bp8 = (nitf_Uint8 *) (bp32++); + + tmp8 = bp8[0]; + bp8[0] = bp8[3]; + bp8[3] = tmp8; + tmp8 = bp8[1]; + bp8[1] = bp8[2]; + bp8[2] = tmp8; + + tmp32 = *bp32 << shift; + *(bp32++) = tmp32 >> shift; + } + + return; +} + + +/* Uses 64 bit types */ +void nitf_ImageIO_unformatSwapExtend_8(nitf_Uint8 * buffer, + size_t count, + nitf_Uint32 shiftCount) +{ + nitf_Int64 shift; /* Shift count */ + nitf_Uint8 *bp8; /* Buffer pointer, 8 bit */ + nitf_Int64 *bp64; /* Buffer pointer, 64 bit */ + nitf_Uint8 tmp8; /* Temp value, 8 bit */ + nitf_Uint64 tmp64; /* Temp value, 64 bit */ + size_t i; + + shift = (nitf_Int64) shiftCount; + bp64 = (nitf_Int64 *) buffer; + for (i = 0; i < count; i++) + { + bp8 = (nitf_Uint8 *) bp64; + + tmp8 = bp8[0]; + bp8[0] = bp8[7]; + bp8[7] = tmp8; + tmp8 = bp8[1]; + bp8[1] = bp8[6]; + bp8[6] = tmp8; + tmp8 = bp8[2]; + bp8[2] = bp8[5]; + bp8[5] = tmp8; + tmp8 = bp8[3]; + bp8[3] = bp8[4]; + bp8[4] = tmp8; + + tmp64 = *bp64 << shift; + *(bp64++) = tmp64 >> shift; + } + + return; +} + + +void nitf_ImageIO_unformatSwapShift_2(nitf_Uint8 * buffer, + size_t count, + nitf_Uint32 shiftCount) +{ + nitf_Int16 shift; /* Shift count */ + nitf_Uint8 *bp8; /* Buffer pointer, 8 bit */ + nitf_Int16 *bp16; /* Buffer pointer, 16 bit */ + nitf_Uint8 tmp8; /* Temp value, 8 bit */ + size_t i; + + shift = (nitf_Int16) shiftCount; + bp16 = (nitf_Int16 *) buffer; + for (i = 0; i < count; i++) + { + bp8 = (nitf_Uint8 *) bp16; + tmp8 = bp8[0]; + bp8[0] = bp8[1]; + bp8[1] = tmp8; + + *(bp16++) >>= shift; + } + + return; +} + + +void nitf_ImageIO_unformatSwapShift_4(nitf_Uint8 * buffer, + size_t count, + nitf_Uint32 shiftCount) +{ + nitf_Int32 shift; /* Shift count */ + nitf_Uint8 *bp8; /* Buffer pointer, 8 bit */ + nitf_Int32 *bp32; /* Buffer pointer, 32 bit */ + nitf_Uint8 tmp8; /* Temp value, 8 bit */ + size_t i; + + shift = (nitf_Int32) shiftCount; + bp32 = (nitf_Int32 *) buffer; + for (i = 0; i < count; i++) + { + bp8 = (nitf_Uint8 *) bp32; + + tmp8 = bp8[0]; + bp8[0] = bp8[3]; + bp8[3] = tmp8; + tmp8 = bp8[1]; + bp8[1] = bp8[2]; + bp8[2] = tmp8; + + *(bp32++) >>= shift; + } + + return; +} + + +/* Uses 64 bit types */ +void nitf_ImageIO_unformatSwapShift_8(nitf_Uint8 * buffer, + size_t count, + nitf_Uint32 shiftCount) +{ + nitf_Int64 shift; /* Shift count */ + nitf_Uint8 *bp8; /* Buffer pointer, 8 bit */ + nitf_Int64 *bp64; /* Buffer pointer, 64 bit */ + nitf_Uint8 tmp8; /* Temp value, 8 bit */ + size_t i; + + shift = (nitf_Int64) shiftCount; + bp64 = (nitf_Int64 *) buffer; + for (i = 0; i < count; i++) + { + bp8 = (nitf_Uint8 *) bp64; + + tmp8 = bp8[0]; + bp8[0] = bp8[7]; + bp8[7] = tmp8; + tmp8 = bp8[1]; + bp8[1] = bp8[6]; + bp8[6] = tmp8; + tmp8 = bp8[2]; + bp8[2] = bp8[5]; + bp8[5] = tmp8; + tmp8 = bp8[3]; + bp8[3] = bp8[4]; + bp8[4] = tmp8; + + *(bp64++) >>= shift; + } + + return; +} + + +void nitf_ImageIO_unformatSwapUShift_2(nitf_Uint8 * buffer, + size_t count, + nitf_Uint32 shiftCount) +{ + nitf_Uint16 shift; /* Shift count */ + nitf_Uint8 *bp8; /* Buffer pointer, 8 bit */ + nitf_Uint16 *bp16; /* Buffer pointer, 16 bit */ + nitf_Uint8 tmp8; /* Temp value, 8 bit */ + size_t i; + + shift = (nitf_Uint16) shiftCount; + bp16 = (nitf_Uint16 *) buffer; + for (i = 0; i < count; i++) + { + bp8 = (nitf_Uint8 *) bp16; + tmp8 = bp8[0]; + bp8[0] = bp8[1]; + bp8[1] = tmp8; + + *(bp16++) >>= shift; + } + + return; +} + +void nitf_ImageIO_unformatSwapUShift_4(nitf_Uint8 * buffer, + size_t count, + nitf_Uint32 shiftCount) +{ + nitf_Uint32 shift; /* Shift count */ + nitf_Uint8 *bp8; /* Buffer pointer, 8 bit */ + nitf_Uint32 *bp32; /* Buffer pointer, 32 bit */ + nitf_Uint8 tmp8; /* Temp value, 8 bit */ + size_t i; + + shift = (nitf_Uint32) shiftCount; + bp32 = (nitf_Uint32 *) buffer; + for (i = 0; i < count; i++) + { + bp8 = (nitf_Uint8 *) bp32; + + tmp8 = bp8[0]; + bp8[0] = bp8[3]; + bp8[3] = tmp8; + tmp8 = bp8[1]; + bp8[1] = bp8[2]; + bp8[2] = tmp8; + + *(bp32++) >>= shift; + } + + return; +} + + +/* Uses 64 bit types */ +void nitf_ImageIO_unformatSwapUShift_8(nitf_Uint8 * buffer, + size_t count, + nitf_Uint32 shiftCount) +{ + nitf_Uint64 shift; /* Shift count */ + nitf_Uint8 *bp8; /* Buffer pointer, 8 bit */ + nitf_Uint64 *bp64; /* Buffer pointer, 64 bit */ + nitf_Uint8 tmp8; /* Temp value, 8 bit */ + size_t i; + + shift = (nitf_Uint64) shiftCount; + bp64 = (nitf_Uint64 *) buffer; + for (i = 0; i < count; i++) + { + bp8 = (nitf_Uint8 *) bp64; + + tmp8 = bp8[0]; + bp8[0] = bp8[7]; + bp8[7] = tmp8; + tmp8 = bp8[1]; + bp8[1] = bp8[6]; + bp8[6] = tmp8; + tmp8 = bp8[2]; + bp8[2] = bp8[5]; + bp8[5] = tmp8; + tmp8 = bp8[3]; + bp8[3] = bp8[4]; + bp8[4] = tmp8; + + *(bp64++) >>= shift; + } + + return; +} + + +void nitf_ImageIO_unpack_P_1(_nitf_ImageIOBlock * blockIO, + nitf_Error * error) +{ + nitf_Uint8 *src; /* Source buffer */ + nitf_Uint8 *dst; /* Destination buffer */ + size_t count; /* Number of pixels to transfer */ + nitf_Uint32 skip; /* Source buffer skip count */ + size_t i; + + /* Silence compiler warnings about unused variables */ + (void)error; + + src = (nitf_Uint8 *) (blockIO->rwBuffer.buffer + + blockIO->rwBuffer.offset.mark); + dst = (nitf_Uint8 *) (blockIO->unpacked.buffer + + blockIO->unpacked.offset.mark); + count = blockIO->pixelCountFR; + skip = blockIO->cntl->nitf->numBands; + + for (i = 0; i < count; i++) + { + *(dst++) = *src; + src += skip; + } + return; +} + + +void nitf_ImageIO_unpack_P_2(_nitf_ImageIOBlock * blockIO, + nitf_Error * error) +{ + nitf_Uint16 *src; /* Source buffer */ + nitf_Uint16 *dst; /* Destination buffer */ + size_t count; /* Number of pixels to transfer */ + nitf_Uint32 skip; /* Source buffer skip count */ + size_t i; + + /* Silence compiler warnings about unused variables */ + (void)error; + + src = (nitf_Uint16 *) (blockIO->rwBuffer.buffer + + blockIO->rwBuffer.offset.mark); + dst = (nitf_Uint16 *) (blockIO->unpacked.buffer + + blockIO->unpacked.offset.mark); + count = blockIO->pixelCountFR; + skip = blockIO->cntl->nitf->numBands; + + for (i = 0; i < count; i++) + { + *(dst++) = *src; + src += skip; + } + return; +} + + +void nitf_ImageIO_unpack_P_4(_nitf_ImageIOBlock * blockIO, + nitf_Error * error) +{ + nitf_Uint32 *src; /* Source buffer */ + nitf_Uint32 *dst; /* Destination buffer */ + size_t count; /* Number of pixels to transfer */ + nitf_Uint32 skip; /* Source buffer skip count */ + size_t i; + + /* Silence compiler warnings about unused variables */ + (void)error; + + src = (nitf_Uint32 *) (blockIO->rwBuffer.buffer + + blockIO->rwBuffer.offset.mark); + dst = (nitf_Uint32 *) (blockIO->unpacked.buffer + + blockIO->unpacked.offset.mark); + count = blockIO->pixelCountFR; + skip = blockIO->cntl->nitf->numBands; + + for (i = 0; i < count; i++) + { + *(dst++) = *src; + src += skip; + } + return; +} + + +void nitf_ImageIO_unpack_P_8(_nitf_ImageIOBlock * blockIO, + nitf_Error * error) +{ + nitf_Uint64 *src; /* Source buffer */ + nitf_Uint64 *dst; /* Destination buffer */ + size_t count; /* Number of pixels to transfer */ + nitf_Uint32 skip; /* Source buffer skip count */ + size_t i; + + /* Silence compiler warnings about unused variables */ + (void)error; + + src = (nitf_Uint64 *) (blockIO->rwBuffer.buffer + + blockIO->rwBuffer.offset.mark); + dst = (nitf_Uint64 *) (blockIO->unpacked.buffer + + blockIO->unpacked.offset.mark); + count = blockIO->pixelCountFR; + skip = blockIO->cntl->nitf->numBands; + + for (i = 0; i < count; i++) + { + *(dst++) = *src; + src += skip; + } + return; +} + + +void nitf_ImageIO_unpack_P_16(_nitf_ImageIOBlock * blockIO, + nitf_Error * error) +{ + nitf_Uint64 *src1; /* Source buffer 1 */ + nitf_Uint64 *dst1; /* Destination buffer 1 */ + nitf_Uint64 *src2; /* Source buffer 2 */ + nitf_Uint64 *dst2; /* Destination buffer 2 */ + size_t count; /* Number of pixels to transfer */ + nitf_Uint32 skip; /* Source buffer skip count */ + size_t i; + + /* Silence compiler warnings about unused variables */ + (void)error; + + src1 = (nitf_Uint64 *) (blockIO->rwBuffer.buffer + + blockIO->rwBuffer.offset.mark); + dst1 = (nitf_Uint64 *) (blockIO->unpacked.buffer + + blockIO->unpacked.offset.mark); + src2 = src1 + 1; + dst2 = dst1 + 1; + count = blockIO->pixelCountFR; + skip = blockIO->cntl->nitf->numBands * 2; + + for (i = 0; i < count; i++) + { + *(dst1++) = *src1; + *(dst2++) = *src2; + src1 += skip; + src2 += skip; + } + return; +} + +void nitf_ImageIO_pack_P_1(_nitf_ImageIOBlock * blockIO, nitf_Error * error) +{ + nitf_Uint8 *src; /* Source buffer */ + nitf_Uint8 *dst; /* Destination buffer */ + size_t count; /* Number of pixels to transfer */ + nitf_Uint32 skip; /* Source buffer skip count */ + size_t i; + + /* Silence compiler warnings about unused variables */ + (void)error; + + src = (nitf_Uint8 *) (blockIO->user.buffer + blockIO->user.offset.mark); + dst = (nitf_Uint8 *) (blockIO->rwBuffer.buffer); + dst += blockIO->band; + count = blockIO->pixelCountFR; + skip = blockIO->cntl->nitf->numBands; + + for (i = 0; i < count; i++) + { + *dst = *(src++); + dst += skip; + } + return; +} + + +void nitf_ImageIO_pack_P_2(_nitf_ImageIOBlock * blockIO, nitf_Error * error) +{ + nitf_Uint16 *src; /* Source buffer */ + nitf_Uint16 *dst; /* Destination buffer */ + size_t count; /* Number of pixels to transfer */ + nitf_Uint32 skip; /* Source buffer skip count */ + size_t i; + + /* Silence compiler warnings about unused variables */ + (void)error; + + src = (nitf_Uint16 *) (blockIO->user.buffer + blockIO->user.offset.mark); + dst = (nitf_Uint16 *) (blockIO->rwBuffer.buffer); + dst += blockIO->band; + count = blockIO->pixelCountFR; + skip = blockIO->cntl->nitf->numBands; + + for (i = 0; i < count; i++) + { + *dst = *(src++); + dst += skip; + } + return; +} + + +void nitf_ImageIO_pack_P_4(_nitf_ImageIOBlock * blockIO, nitf_Error * error) +{ + nitf_Uint32 *src; /* Source buffer */ + nitf_Uint32 *dst; /* Destination buffer */ + size_t count; /* Number of pixels to transfer */ + nitf_Uint32 skip; /* Source buffer skip count */ + size_t i; + + /* Silence compiler warnings about unused variables */ + (void)error; + + src = (nitf_Uint32 *) (blockIO->user.buffer + blockIO->user.offset.mark); + dst = (nitf_Uint32 *) (blockIO->rwBuffer.buffer); + dst += blockIO->band; + count = blockIO->pixelCountFR; + skip = blockIO->cntl->nitf->numBands; + + for (i = 0; i < count; i++) + { + *dst = *(src++); + dst += skip; + } + return; +} + + +void nitf_ImageIO_pack_P_8(_nitf_ImageIOBlock * blockIO, nitf_Error * error) +{ + nitf_Uint64 *src; /* Source buffer */ + nitf_Uint64 *dst; /* Destination buffer */ + size_t count; /* Number of pixels to transfer */ + nitf_Uint32 skip; /* Source buffer skip count */ + size_t i; + + /* Silence compiler warnings about unused variables */ + (void)error; + + src = (nitf_Uint64 *) (blockIO->user.buffer + blockIO->user.offset.mark); + dst = (nitf_Uint64 *) (blockIO->rwBuffer.buffer); + dst += blockIO->band; + count = blockIO->pixelCountFR; + skip = blockIO->cntl->nitf->numBands; + + for (i = 0; i < count; i++) + { + *dst = *(src++); + dst += skip; + } + return; +} + + +void nitf_ImageIO_pack_P_16(_nitf_ImageIOBlock * blockIO, nitf_Error * error) +{ + nitf_Uint64 *src1; /* Source buffer 1 */ + nitf_Uint64 *dst1; /* Destination buffer 1 */ + nitf_Uint64 *src2; /* Source buffer 2 */ + nitf_Uint64 *dst2; /* Destination buffer 2 */ + size_t count; /* Number of pixels to transfer */ + nitf_Uint32 skip; /* Source buffer skip count */ + size_t i; + + /* Silence compiler warnings about unused variables */ + (void)error; + + src1 = (nitf_Uint64 *) (blockIO->user.buffer + blockIO->user.offset.mark); + dst1 = (nitf_Uint64 *) (blockIO->rwBuffer.buffer); + dst1 += blockIO->band; + src2 = src1 + 1; + dst2 = dst1 + 1; + count = blockIO->pixelCountFR; + skip = blockIO->cntl->nitf->numBands * 2; + + for (i = 0; i < count; i++) + { + *dst1 = *(src1++); + *dst2 = *(src2++); + dst1 += skip; + dst2 += skip; + } + return; +} + +void nitf_ImageIO_formatShift_1(nitf_Uint8 * buffer, + size_t count, nitf_Uint32 shiftCount) +{ + nitf_Int8 shift; /* Shift count */ + nitf_Int8 *bp8; /* Buffer pointer, 8 bit */ + size_t i; + + shift = (nitf_Int8) shiftCount; + bp8 = (nitf_Int8 *) buffer; + for (i = 0; i < count; i++) + *(bp8++) <<= shift; + + return; +} + + +void nitf_ImageIO_formatShift_2(nitf_Uint8 * buffer, + size_t count, nitf_Uint32 shiftCount) +{ + nitf_Int16 shift; /* Shift count */ + nitf_Int16 *bp16; /* Buffer pointer, 16 bit */ + size_t i; + + shift = (nitf_Int16) shiftCount; + bp16 = (nitf_Int16 *) buffer; + for (i = 0; i < count; i++) + *(bp16++) <<= shift; + + return; +} + + +void nitf_ImageIO_formatShift_4(nitf_Uint8 * buffer, + size_t count, nitf_Uint32 shiftCount) +{ + nitf_Int32 shift; /* Shift count */ + nitf_Int32 *bp32; /* Buffer pointer, 32 bit */ + size_t i; + + shift = (nitf_Int32) shiftCount; + bp32 = (nitf_Int32 *) buffer; + for (i = 0; i < count; i++) + *(bp32++) <<= shift; + + return; +} + + +/* Uses 64 bit types */ + +void nitf_ImageIO_formatShift_8(nitf_Uint8 * buffer, + size_t count, nitf_Uint32 shiftCount) +{ + nitf_Int64 shift; /* Shift count */ + nitf_Int64 *bp64; /* Buffer pointer, 64 bit */ + size_t i; + + shift = (nitf_Int64) shiftCount; + bp64 = (nitf_Int64 *) buffer; + for (i = 0; i < count; i++) + *(bp64++) <<= shift; + + return; +} + +void nitf_ImageIO_formatMask_1(nitf_Uint8 * buffer, + size_t count, nitf_Uint32 shiftCount) +{ + nitf_Uint8 mask; /* The mask */ + nitf_Uint8 *bp8; /* Buffer pointer, 8 bit */ + size_t i; + + mask = ((nitf_Uint8) - 1) << (8 - shiftCount); + bp8 = (nitf_Uint8 *) buffer; + for (i = 0; i < count; i++) + *(bp8++) &= mask; + + return; +} + +void nitf_ImageIO_formatMask_2(nitf_Uint8 * buffer, + size_t count, nitf_Uint32 shiftCount) +{ + nitf_Uint8 mask; /* The mask */ + nitf_Uint16 *bp16; /* Buffer pointer, 16 bit */ + size_t i; + + mask = ((nitf_Uint16) - 1) << (16 - shiftCount); + bp16 = (nitf_Uint16 *) buffer; + for (i = 0; i < count; i++) + *(bp16++) &= mask; + + return; +} + + +void nitf_ImageIO_formatMask_4(nitf_Uint8 * buffer, + size_t count, nitf_Uint32 shiftCount) +{ + nitf_Uint8 mask; /* The mask */ + nitf_Uint32 *bp32; /* Buffer pointer, 32 bit */ + size_t i; + + mask = ((nitf_Uint32) - 1) << (32 - shiftCount); + bp32 = (nitf_Uint32 *) buffer; + for (i = 0; i < count; i++) + *(bp32++) &= mask; + + return; +} + + +/* Uses 64 bit types */ + +void nitf_ImageIO_formatMask_8(nitf_Uint8 * buffer, + size_t count, nitf_Uint32 shiftCount) +{ + nitf_Uint8 mask; /* The mask */ + nitf_Uint64 *bp64; /* Buffer pointer, 64 bit */ + size_t i; + + mask = ((nitf_Uint64) - 1) << (64 - shiftCount); + bp64 = (nitf_Uint64 *) buffer; + for (i = 0; i < count; i++) + *(bp64++) &= mask; + + return; +} + + +void nitf_ImageIO_formatShiftSwap_2(nitf_Uint8 * buffer, + size_t count, + nitf_Uint32 shiftCount) +{ + nitf_Int16 shift; /* Shift count */ + nitf_Uint8 *bp8; /* Buffer pointer, 8 bit */ + nitf_Int16 *bp16; /* Buffer pointer, 16 bit */ + nitf_Uint8 tmp8; /* Temp value, 8 bit */ + size_t i; + + shift = (nitf_Int16) shiftCount; + bp16 = (nitf_Int16 *) buffer; + for (i = 0; i < count; i++) + { + bp8 = (nitf_Uint8 *) bp16; + tmp8 = bp8[0]; + bp8[0] = bp8[1]; + bp8[1] = tmp8; + + *(bp16++) >>= shift; + } + + return; +} + + +void nitf_ImageIO_formatShiftSwap_4(nitf_Uint8 * buffer, + size_t count, + nitf_Uint32 shiftCount) +{ + nitf_Int32 shift; /* Shift count */ + nitf_Uint8 *bp8; /* Buffer pointer, 8 bit */ + nitf_Int32 *bp32; /* Buffer pointer, 32 bit */ + nitf_Uint8 tmp8; /* Temp value, 8 bit */ + size_t i; + + shift = (nitf_Int32) shiftCount; + bp32 = (nitf_Int32 *) buffer; + for (i = 0; i < count; i++) + { + bp8 = (nitf_Uint8 *) bp32; + + tmp8 = bp8[0]; + bp8[0] = bp8[3]; + bp8[3] = tmp8; + tmp8 = bp8[1]; + bp8[1] = bp8[2]; + bp8[2] = tmp8; + + *(bp32++) >>= shift; + } + + return; +} + + +/* Uses 64 bit types */ +void nitf_ImageIO_formatShiftSwap_8(nitf_Uint8 * buffer, + size_t count, + nitf_Uint32 shiftCount) +{ + nitf_Int64 shift; /* Shift count */ + nitf_Uint8 *bp8; /* Buffer pointer, 8 bit */ + nitf_Int64 *bp64; /* Buffer pointer, 64 bit */ + nitf_Uint8 tmp8; /* Temp value, 8 bit */ + size_t i; + + shift = (nitf_Int64) shiftCount; + bp64 = (nitf_Int64 *) buffer; + for (i = 0; i < count; i++) + { + bp8 = (nitf_Uint8 *) bp64; + + tmp8 = bp8[0]; + bp8[0] = bp8[7]; + bp8[7] = tmp8; + tmp8 = bp8[1]; + bp8[1] = bp8[6]; + bp8[6] = tmp8; + tmp8 = bp8[2]; + bp8[2] = bp8[5]; + bp8[5] = tmp8; + tmp8 = bp8[3]; + bp8[3] = bp8[4]; + bp8[4] = tmp8; + + *(bp64++) >>= shift; + } + + return; +} + + +void nitf_ImageIO_formatMaskSwap_2(nitf_Uint8 * buffer, + size_t count, + nitf_Uint32 shiftCount) +{ + nitf_Uint8 mask; /* The mask */ + nitf_Uint8 *bp8; /* Buffer pointer, 8 bit */ + nitf_Uint16 *bp16; /* Buffer pointer, 16 bit */ + nitf_Uint8 tmp8; /* Temp value, 8 bit */ + size_t i; + + mask = ((nitf_Uint16) - 1) << (16 - shiftCount); + bp16 = (nitf_Uint16 *) buffer; + for (i = 0; i < count; i++) + { + *(bp16++) &= mask; + + bp8 = (nitf_Uint8 *) bp16; + tmp8 = bp8[0]; + bp8[0] = bp8[1]; + bp8[1] = tmp8; + } + + return; +} + + +void nitf_ImageIO_formatMaskSwap_4(nitf_Uint8 * buffer, + size_t count, + nitf_Uint32 shiftCount) +{ + nitf_Uint8 mask; /* The mask */ + nitf_Uint8 *bp8; /* Buffer pointer, 8 bit */ + nitf_Uint32 *bp32; /* Buffer pointer, 32 bit */ + nitf_Uint8 tmp8; /* Temp value, 8 bit */ + size_t i; + + mask = ((nitf_Uint32) - 1) << (32 - shiftCount); + bp32 = (nitf_Uint32 *) buffer; + for (i = 0; i < count; i++) + { + bp8 = (nitf_Uint8 *) bp32; + + *(bp32++) &= mask; + + tmp8 = bp8[0]; + bp8[0] = bp8[3]; + bp8[3] = tmp8; + tmp8 = bp8[1]; + bp8[1] = bp8[2]; + bp8[2] = tmp8; + } + + return; +} + + +/* Uses 64 bit types */ +void nitf_ImageIO_formatMaskSwap_8(nitf_Uint8 * buffer, + size_t count, + nitf_Uint32 shiftCount) +{ + nitf_Uint8 mask; /* The mask */ + nitf_Uint8 *bp8; /* Buffer pointer, 8 bit */ + nitf_Uint64 *bp64; /* Buffer pointer, 64 bit */ + nitf_Uint8 tmp8; /* Temp value, 8 bit */ + size_t i; + + mask = ((nitf_Uint64) - 1) << (64 - shiftCount); + bp64 = (nitf_Uint64 *) buffer; + for (i = 0; i < count; i++) + { + bp8 = (nitf_Uint8 *) bp64; + + *(bp64++) &= mask; + + tmp8 = bp8[0]; + bp8[0] = bp8[7]; + bp8[7] = tmp8; + tmp8 = bp8[1]; + bp8[1] = bp8[6]; + bp8[6] = tmp8; + tmp8 = bp8[2]; + bp8[2] = bp8[5]; + bp8[5] = tmp8; + tmp8 = bp8[3]; + bp8[3] = bp8[4]; + bp8[4] = tmp8; + } + + return; +} + + +/*============================================================================*/ +/*======================== B pixel type psuedo decompressor ==================*/ +/*============================================================================*/ + +NITFPRIV(NITF_BOOL) nitf_ImageIO_bPixelFreeBlock(nitf_DecompressionControl + * control, + nitf_Uint8 * block, + nitf_Error * error) +{ + /* Silence compiler warnings about unused variables */ + (void)control; + (void)error; + + NITF_FREE(block); + return NITF_SUCCESS; +} + + +NITFPRIV(nitf_DecompressionControl*) +nitf_ImageIO_bPixelOpen(nitf_ImageSubheader * subheader, + nrt_HashTable * options, + nitf_Error * error) +{ + nitf_ImageIO_BPixelControl *icntl; + (void)subheader; + (void)options; + + icntl = (nitf_ImageIO_BPixelControl *) + NITF_MALLOC(sizeof(nitf_ImageIO_BPixelControl)); + if (icntl == NULL) + { + nitf_Error_init(error, "Error creating control object", + NITF_CTXT, NITF_ERR_DECOMPRESSION); + return NULL; + } + + return (nitf_DecompressionControl *) icntl; +} + +NITFPRIV(NITF_BOOL) nitf_ImageIO_bPixelStart(nitf_DecompressionControl * control, + nitf_IOInterface* io, + nitf_Uint64 offset, + nitf_Uint64 fileLength, + nitf_BlockingInfo * blockInfo, + nitf_Uint64 * blockMask, + nitf_Error * error) +{ + nitf_ImageIO_BPixelControl *icntl; + + icntl = (nitf_ImageIO_BPixelControl *)control; + + /* Silence compiler warnings about unused variables */ + (void)fileLength; + + icntl->io = io; + icntl->offset = offset; + icntl->blockInfo = blockInfo; + icntl->blockMask = blockMask; + icntl->blockSizeCompressed = (blockInfo->length + 7) / 8; + icntl->buffer = (nitf_Uint8 *) NITF_MALLOC(icntl->blockSizeCompressed); + if (icntl->buffer == NULL) + { + nitf_Error_init(error, "Error creating control object", + NITF_CTXT, NITF_ERR_DECOMPRESSION); + NITF_FREE(icntl); + return NITF_FAILURE; + } + + return NITF_SUCCESS; +} + + +NITFPRIV(nitf_Uint8 *) +nitf_ImageIO_bPixelReadBlock(nitf_DecompressionControl * control, + nitf_Uint32 blockNumber, + nitf_Uint64* blockSize, + nitf_Error * error) +{ + /* Actual control type */ + nitf_ImageIO_BPixelControl *icntl; + size_t uncompressedLen; /* Length of uncompressed block */ + nitf_Uint8 *block; /* Uncompressed result */ + nitf_Uint8 *blockPtr; /* Pointer in uncompressed result */ + nitf_Uint8 *compPtr; /* Pointer in compressed input */ + nitf_Uint8 current; /* Current byte of compressed data */ + size_t i; + + icntl = (nitf_ImageIO_BPixelControl *) control; + uncompressedLen = icntl->blockInfo->length; + + /* Read the data */ + + if (!NITF_IO_SUCCESS(nitf_IOInterface_seek(icntl->io, + (nitf_Off) (icntl->offset + + icntl-> + blockMask + [blockNumber]), + NITF_SEEK_SET, error))) + return NULL; + + if (!nitf_IOInterface_read(icntl->io, + (char *) (icntl->buffer), + icntl->blockSizeCompressed, error)) + return NULL; + + /* Allocate block */ + + block = (nitf_Uint8 *) NITF_MALLOC(uncompressedLen); + if (block == NULL) + { + nitf_Error_init(error, "Error creating block buffer", + NITF_CTXT, NITF_ERR_DECOMPRESSION); + return NULL; + } + + /* Decompress the result */ + + blockPtr = block; + compPtr = icntl->buffer; + current = 0; /* Avoids uninitialized variable warning */ + for (i = 0; i < uncompressedLen; i++) + { + if (i % 8 == 0) + current = *(compPtr++); + *(blockPtr++) = (current & 0x80) ? 1 : 0; + current <<= 1; + } + + *blockSize = uncompressedLen; + return block; +} + + +NITFPRIV(void) +nitf_ImageIO_bPixelClose(nitf_DecompressionControl **control) +{ + nitf_ImageIO_BPixelControl *icntl; + icntl = (nitf_ImageIO_BPixelControl *) * control; + + if (icntl->buffer != NULL) + NITF_FREE((void *) (icntl->buffer)); + NITF_FREE((void *) (icntl)); + *control = NULL; + return; +} + + +/*============================================================================*/ +/*======================== 12-bit pixel type psuedo decompressor =============*/ +/*============================================================================*/ + +NITFPRIV(NITF_BOOL) nitf_ImageIO_12PixelFreeBlock(nitf_DecompressionControl + * control, + nitf_Uint8 * block, + nitf_Error * error) +{ + /* Silence compiler warnings about unused variables */ + (void)control; + (void)error; + + NITF_FREE(block); + return NITF_SUCCESS; +} + +NITFPRIV(nitf_DecompressionControl*) +nitf_ImageIO_12PixelOpen(nitf_ImageSubheader * subheader, + nrt_HashTable * options, + nitf_Error * error) +{ + nitf_ImageIO_12PixelControl *icntl; + (void)subheader; + (void)options; + + icntl = + (nitf_ImageIO_12PixelControl *) + NITF_MALLOC(sizeof(nitf_ImageIO_12PixelControl)); + if (icntl == NULL) + { + nitf_Error_init(error, "Error creating control object", + NITF_CTXT, NITF_ERR_DECOMPRESSION); + return NULL; + } + + return (nitf_DecompressionControl *) icntl; +} + +NITFPRIV(NITF_BOOL) +nitf_ImageIO_12PixelStart(nitf_DecompressionControl* control, + nitf_IOInterface* io, + nitf_Uint64 offset, + nitf_Uint64 fileLength, + nitf_BlockingInfo * blockInfo, + nitf_Uint64 * blockMask, + nitf_Error * error) +{ + nitf_ImageIO_12PixelControl *icntl; + + /* Silence compiler warnings about unused variables */ + (void)fileLength; + + icntl = (nitf_ImageIO_12PixelControl *)control; + icntl->io = io; + icntl->offset = offset; + icntl->blockInfo = blockInfo; + icntl->blockMask = blockMask; + icntl->blockPixelCount = blockInfo->length/2; + if(icntl->blockPixelCount & 1) /* Odd number of pixels in block */ + icntl->odd = 1; + else /* Even number of pixels in block */ + icntl->odd = 0; +/* + The 12-bit pixel arrangement puts 2 pixels (24 bits) in three bytes. + If the pixel count is odd the last pixel is packed into 2 bytes. So + The calculation of the size of the compress block has to consider whether + the pixel count is odd or even +*/ + + icntl->blockSizeCompressed = 3*(icntl->blockPixelCount/2) + 2*(icntl->odd); + + icntl->buffer = (nitf_Uint8 *) NITF_MALLOC(icntl->blockSizeCompressed); + if (icntl->buffer == NULL) + { + nitf_Error_init(error, "Error creating control object", + NITF_CTXT, NITF_ERR_DECOMPRESSION); + NITF_FREE(icntl); + return NITF_FAILURE; + } + + return NITF_SUCCESS; +} + +NITFPRIV(nitf_Uint8 *) +nitf_ImageIO_12PixelReadBlock(nitf_DecompressionControl* control, + nitf_Uint32 blockNumber, + nitf_Uint64* blockSize, + nitf_Error* error) +{ + /* Actual control type */ + nitf_ImageIO_12PixelControl *icntl; + size_t uncompressedLen; /* Length of uncompressed block */ + nitf_Uint8 *block; /* Uncompressed result */ + nitf_Uint16 *blockPtr; /* Pointer in uncompressed result */ + nitf_Uint8 *compPtr; /* Pointer in compressed input */ + nitf_Uint16 a; /* Components of compressed pixel */ + nitf_Uint16 b; + nitf_Uint16 c; + size_t i; + + icntl = (nitf_ImageIO_12PixelControl *) control; + uncompressedLen = icntl->blockInfo->length; + + /* Read the data */ + + if (!NITF_IO_SUCCESS(nitf_IOInterface_seek(icntl->io, + (nitf_Off) (icntl->offset + icntl->blockMask[blockNumber]), + NITF_SEEK_SET, error))) + return NULL; + + if (!nitf_IOInterface_read(icntl->io, + (char *) (icntl->buffer), + icntl->blockSizeCompressed, error)) + return NULL; + + /* Allocate block */ + + block = (nitf_Uint8 *) NITF_MALLOC(uncompressedLen); + if (block == NULL) + { + nitf_Error_init(error, "Error creating block buffer", + NITF_CTXT, NITF_ERR_DECOMPRESSION); + return NULL; + } + + /* Decompress the result */ + + blockPtr = (nitf_Uint16 *) block; + compPtr = icntl->buffer; + for (i = 0; i < icntl->blockPixelCount/2; i++) + { + a = *(compPtr++); + b = *(compPtr++); + c = *(compPtr++); + + *(blockPtr++) = (a << 4) + (b >> 4); + *(blockPtr++) = ((b << 8) & 0xf00) + c; + } + + if(icntl->odd) /* Look for odd count and handle last pixel */ + { + a = *(compPtr++); + b = *(compPtr++); + + *(blockPtr++) = (a << 4) + (b >>4); + } + + *blockSize = icntl->blockPixelCount * sizeof(nitf_Uint16); + + return block; +} + + +NITFPRIV(void) +nitf_ImageIO_12PixelClose(nitf_DecompressionControl **control) +{ + nitf_ImageIO_12PixelControl *icntl; + icntl = (nitf_ImageIO_12PixelControl *) * control; + + if (icntl->buffer != NULL) + NITF_FREE((void *) (icntl->buffer)); + NITF_FREE((void *) (icntl)); + *control = NULL; + return; +} + +/*============================================================================*/ +/*======================== 12-bit pixel type pseudo compressor =============*/ +/*============================================================================*/ + +nitf_CompressionControl *nitf_ImageIO_12PixelComOpen +( nitf_ImageSubheader * subheader, nrt_HashTable* options, nitf_Error * error) +{ + nitf_ImageIO_12PixelComControl *icntl; /* The result */ + nitf_Uint32 numRowsPerBlock; /* Number of rows per block */ + nitf_Uint32 numColumnsPerBlock; /* Number of columns per block */ + nitf_Uint32 numBands, xBands; /* Number of bands */ + + icntl = + (nitf_ImageIO_12PixelComControl *) + NITF_MALLOC(sizeof(nitf_ImageIO_12PixelComControl)); + if (icntl == NULL) + { + nitf_Error_init(error, "Error creating control object", + NITF_CTXT, NITF_ERR_COMPRESSION); + return(NULL); + } + +/* Get values from the subheader, need block dimensions */ + + NITF_TRY_GET_UINT32(subheader->numImageBands, &numBands, error); + NITF_TRY_GET_UINT32(subheader->numMultispectralImageBands, &xBands, error); + numBands += xBands; + NITF_TRY_GET_UINT32(subheader->numPixelsPerVertBlock,&numRowsPerBlock, error); + NITF_TRY_GET_UINT32(subheader->numPixelsPerHorizBlock,&numColumnsPerBlock, + error); + +/* Does not work for S mode which is not supported */ + icntl->blockPixelCount = (size_t)numRowsPerBlock*numColumnsPerBlock*numBands; + icntl->odd = icntl->blockPixelCount & 1; + icntl->blockSizeCompressed = 3*(icntl->blockPixelCount/2) + 2*(icntl->odd); + icntl->blockSizeUncompressed = icntl->blockPixelCount*2; + icntl->buffer = NITF_MALLOC(icntl->blockSizeCompressed); + if(icntl->buffer == NULL) + { + nitf_Error_init(error, "Error creating control object", + NITF_CTXT, NITF_ERR_COMPRESSION); + NITF_FREE(icntl); + return(NULL); + } + + + return((nitf_CompressionControl *) icntl); + +CATCH_ERROR: + NITF_FREE(icntl); + return NULL; +} + +NITF_BOOL +nitf_ImageIO_12PixelComStart(nitf_CompressionControl *object, + nitf_Uint64 offset, + nitf_Uint64 dataLength, + nitf_Uint64 * blockMask, + nitf_Uint64 * padMask, + nitf_Error * error) +{ + nitf_ImageIO_12PixelComControl *icntl; /* The internal data structure */ + + /* Silence compiler warnings about unused variables */ + (void)error; + + icntl = (nitf_ImageIO_12PixelComControl *) object; + icntl->io = NULL; + icntl->offset = offset; + icntl->dataLength = dataLength; + icntl->offset = offset; + icntl->blockMask = blockMask; + icntl->padMask = padMask; + icntl->buffer = NULL; + icntl->written = 0; + +/* Allocate compressed block buffer */ + + icntl->buffer = (nitf_Uint8 *) NITF_MALLOC(icntl->blockSizeCompressed); + if(icntl->buffer == NULL) + return(NITF_FAILURE); + + return(NITF_SUCCESS); +} + +NITF_BOOL +nitf_ImageIO_12PixelComWriteBlock(nitf_CompressionControl * object, + nitf_IOInterface* io, + const nitf_Uint8 *data, + NITF_BOOL pad, + NITF_BOOL noData, + nitf_Error *error) +{ + nitf_ImageIO_12PixelComControl *icntl; /* The internal data structure */ + size_t pairs; /* Number of pixel pairs */ + nitf_Uint16 *dp; /* Pointer into input buffer */ + nitf_Uint8 *bp; /* Pointer into output buffer */ + nitf_Uint16 i1; /* First pixel in input pair */ + nitf_Uint16 i2; /* Second pixel in input pair */ + nitf_Off fileOffset; /* File offset for write */ + size_t i; + + /* Silence compiler warnings about unused variables */ + (void)pad; + (void)noData; + + icntl = (nitf_ImageIO_12PixelComControl *) object; + + icntl->io = io; + +/* Compress block into buffer */ + + pairs = icntl->blockPixelCount/2; + bp = icntl->buffer; + dp = (nitf_Uint16 *) data; + for(i=0;i> 4) & 0xff; + *(bp++) = ((i1 & 0x0f) << 4) + ((i2 >> 8) & 0x0f); + *(bp++) = i2 & 0xff; + } + + if(icntl->odd) /* Handle last pixel in odd block length case */ + { + i1 = *dp; + *(bp++) = (i1 >> 4) & 0xff; + *(bp++) = (i1 & 0x0f) << 4; + } + +/* Do the write */ + + fileOffset = icntl->offset + icntl->written; + if(!NITF_IO_SUCCESS( + nitf_IOInterface_seek(io,fileOffset,NITF_SEEK_SET,error))) + return NITF_FAILURE; + + + if(!nitf_IOInterface_write(io,(char *) (icntl->buffer), + icntl->blockSizeCompressed, error)) + return NITF_FAILURE; + + icntl->written += icntl->blockSizeCompressed; + + return(NITF_SUCCESS); +} + +NITF_BOOL nitf_ImageIO_12PixelComEnd +( nitf_CompressionControl * object,nitf_IOInterface* io, nitf_Error *error) +{ + /* Silence compiler warnings about unused variables */ + (void)object; + (void)io; + (void)error; + + return(NITF_SUCCESS); +} + +void nitf_ImageIO_12PixelComDestroy(nitf_CompressionControl ** object) +{ + nitf_ImageIO_12PixelComControl *icntl; /* The internal data structure */ + + icntl = (nitf_ImageIO_12PixelComControl *) object; + + if(object != NULL) + { + icntl = *((nitf_ImageIO_12PixelComControl **) object); + if(icntl != NULL) + { + if(icntl->buffer != NULL) + NITF_FREE(icntl->buffer); + NITF_FREE(icntl); + } + *object = NULL; + } + return; +} + +/*============================================================================*/ +/*======================== Diagnostic Functions ===============================*/ +/*============================================================================*/ + +/*========================= nitf_ImageIO_print ===============================*/ + +NITFPRIV(void) nitf_ImageIO_print(nitf_ImageIO * nitf, FILE * file) +{ +#ifdef NITF_DEBUG + /* Correct type for pointer */ + _nitf_ImageIO *nitfp = (_nitf_ImageIO *) nitf; + int i; + + if (file == NULL) + file = stdout; + + fprintf(file, "nitf_ImageIO structure:\n"); + fprintf(file, " Number of rows: %ld\n", nitfp->numRows); + fprintf(file, " Number of columns: %ld\n", nitfp->numColumns); + fprintf(file, " Number of bands: %ld\n", nitfp->numBands); + + fprintf(file, " Pixel definition:\n"); + fprintf(file, " Pixel type code: %08lx\n", nitfp->pixel.type); + fprintf(file, " Pixel type size in bytes: %08lx\n", + nitfp->pixel.bytes); + fprintf(file, " Pad value: "); + for (i = 0; i < NITF_IMAGE_IO_PAD_MAX_LENGTH; i++) + fprintf(file, "%02x ", nitfp->pixel.pad[i]); + fprintf(file, "\n"); + fprintf(file, " Byte swap if TRUE: %d\n", nitfp->pixel.swap); + fprintf(file, " Shift count for left justified data: %ld\n", + nitfp->pixel.shift); + fprintf(file, " Number of blocks per row: %ld\n", nitfp->nBlocksPerRow); + fprintf(file, " Number of blocks per column: %ld\n", + nitfp->nBlocksPerColumn); + fprintf(file, " Number of rows per block: %ld\n", nitfp->numRowsPerBlock); + fprintf(file, " Number of columns per block: %ld\n", + nitfp->numColumnsPerBlock); + fprintf(file, " Block size in bytes: %ld\n", nitfp->blockSize); + fprintf(file, " Total number of blocks: %ld\n", nitfp->nBlocksTotal); + fprintf(file, " Actual number of rows: %ld\n", nitfp->numRowsActual); + fprintf(file, " Actual number of columns: %ld\n", + nitfp->numColumnsActual); + fprintf(file, " Compression type code: %08lx\n", nitfp->compression); + fprintf(file, " Blocking mode code: %08lx\n", nitfp->blockingMode); + fprintf(file, " File offset to image data section: %llx\n", + nitfp->imageBase); + fprintf(file, " File offset to pixel data: %llx\n", nitfp->pixelBase); + fprintf(file, " Image data length including masks: %llx\n", + nitfp->dataLength); + fprintf(file, " Parameters:\n"); + fprintf(file, + " Request/Block size threshold for no caching: %lf\n", + nitfp->parameters.noCacheThreshold); + fprintf(file, " Clear cache after I/O operation: %ld\n", + nitfp->parameters.clearCache); + fprintf(file, " Block and pad mask header:\n"); + fprintf(file, " Ready flag %d\n", nitfp->maskHeader.ready); + fprintf(file, " Offset to actual image data past masks: %lx\n", + nitfp->maskHeader.imageDataOffset); + fprintf(file, " Block mask record length: %x\n", + nitfp->maskHeader.blockRecordLength); + fprintf(file, " Pad pixel mask record length: %x\n", + nitfp->maskHeader.padRecordLength); + fprintf(file, " Pad pixel value length in bytes: %x\n", + nitfp->maskHeader.padPixelValueLength); + fprintf(file, " Read/write one band at a time if TRUE: %d\n", + nitfp->oneBand); + + fflush(file); +#else + /* Silence compiler warnings about unused variables */ + (void)nitf; + (void)file; +#endif + return; +} + + +NITFPRIV(void) nitf_ImageIOControl_print(_nitf_ImageIOControl * cntl, + FILE * file, int full) +{ +#ifdef NITF_DEBUG + nitf_Uint32 i; + + if (file == NULL) + file = stdout; + + fprintf(file, "nitf_ImageIO control structure:\n"); + fprintf(file, " Number of row in the sub-window: %ld\n", cntl->numRows); + fprintf(file, " Start row in the main image: %ld\n", cntl->row); + fprintf(file, " Row skip factor: %ld\n", cntl->rowSkip); + fprintf(file, " Number of columns in the sub-window: %ld\n", + cntl->numColumns); + fprintf(file, " Start column in the main image: %ld\n", cntl->column); + fprintf(file, " Column skip factor: %ld\n", cntl->columnSkip); + fprintf(file, " Down-sampling flag: %ld\n", cntl->downSampling); + fprintf(file, " Number of bands to read/write: %ld\n", + cntl->numBandSubset); + fprintf(file, " Array of bands to read/write:\n"); + for (i = 0; i < cntl->numBandSubset; i++) + fprintf(file, " %ld", cntl->bandSubset[i]); + fprintf(file, "\n"); + fprintf(file, " Operation is read if TRUE: %d\n", cntl->reading); + fprintf(file, " Number of _nitf_ImageIOBlock structures: %ld\n", + cntl->nBlockIO); + if (full) + { + for (i = 0; i < cntl->nBlockIO; i++) + nitf_ImageIOBlock_print(&(cntl->blockIO[0][0]) + i, file, 1); + } + fprintf(file, " Block number next row increment: %ld\n", + cntl->numberInc); + fprintf(file, + " Data's offset in block next row byte increment: %ld\n", + cntl->blockOffsetInc); + fprintf(file, " Read/write buffer next row byte increment: %ld\n", + cntl->bufferInc); + fprintf(file, " User data buffer next row byte increment: %ld\n", + cntl->userInc); + fprintf(file, " Pad pixel buffer size in bytes: %ld\n", + cntl->padBufferSize); + fprintf(file, " Pad pixels read fla: %d\n", cntl->padded); + fprintf(file, " Total I/O count: %ld I/O count down : %ld\n", + cntl->ioCount, cntl->ioCountDown); + + fflush(file); +#else + /* Silence compiler warnings about unused variables */ + (void)cntl; + (void)file; + (void)full; +#endif + return; +} + +NITFPRIV(void) nitf_ImageIOBlock_print(_nitf_ImageIOBlock * blockIO, + FILE * file, int longIndent) +{ +#ifdef NITF_BLOCK_DEBUG + char *sp; + + if (file == NULL) + file = stdout; + + if (longIndent) + sp = " "; + else + sp = " "; + + if (!longIndent) + fprintf(file, "Block IO control structure:\n"); + + fprintf(file, "%sAssociated nitf_ImageIOControl object:\n", sp); + fprintf(file, "%sBand associated width this I/O: %ld\n", sp, + blockIO->band); + fprintf(file, "%sDo the read/write if TRUE: %d\n", sp, blockIO->doIO); + fprintf(file, "%sBlock number: %ld\n", sp, blockIO->number); + fprintf(file, " Rows until next block: %ld\n", blockIO->rowsUntil); + fprintf(file, "%sBlock's offset from image base: %lx\n", + sp, blockIO->imageDataOffset); + fprintf(file, "%sData's base byte offset in block: %ld\n", + sp, blockIO->blockOffset.orig); + fprintf(file, "%sData's current byte offset in block: %ld\n", + sp, blockIO->blockOffset.mark); + fprintf(file, "%sRead count in bytes: %ld\n", sp, blockIO->readCount); + /*fprintf(file, "%sOffset into read/write buffer: %ld\n", sp, + blockIO->bufferOffset); + fprintf(file, "%sOriginal offset into read/write buffer: %ld\n", sp, + blockIO->bufferOffsetOrg); + fprintf(file, "%sOffset into user buffer: %ld\n", sp, + blockIO->userOffset); + fprintf(file, "%sOriginal offset into user buffer: %ld\n", sp, + blockIO->userOffsetOrg);*/ + fprintf(file, "%sRead/write buffer is user buffer if TRUE: %ld\n", sp, + blockIO->userEqBuffer); + fprintf(file, + "%sPixel count in this operation, full resolution: %ld\n", sp, + blockIO->pixelCountFR); + fprintf(file, + "%sPixel count in this operation, down-sample resolution: %ld\n", + sp, blockIO->pixelCountDR); + fprintf(file, "%sFormat count in this operation: %ld\n", sp, + blockIO->formatCount); + fprintf(file, "%sPad pixel column write byte count: %ld\n", sp, + blockIO->padColumnCount); + fprintf(file, "%sPad pixel row write count: %ld\n", sp, + blockIO->padRowCount); + fprintf(file, "%sStart column of the first new sample window: %ld\n", + sp, blockIO->sampleStartColumn); + fprintf(file, "%sPartial sample columns previous block: %ld\n", sp, + blockIO->residual); + fprintf(file, "%sPartial sample columns current block: %ld\n", sp, + blockIO->myResidual); + fprintf(file, "%sCurrent row in the image: %ld\n", sp, + blockIO->currentRow); + + fflush(file); +#else + /* Silence compiler warnings about unused variables */ + (void)blockIO; + (void)file; + (void)longIndent; +#endif + return; +} + +NITFAPI(NITF_BOOL) nitf_ImageIO_getMaskInfo(nitf_ImageIO *nitf, + nitf_Uint32 *imageDataOffset, + nitf_Uint32 *blockRecordLength, + nitf_Uint32 *padRecordLength, + nitf_Uint32 *padPixelValueLength, + nitf_Uint8 **padValue, + nitf_Uint64 **blockMask, + nitf_Uint64 **padMask) +{ + _nitf_ImageIO *initf = (_nitf_ImageIO *) nitf; + + if ((initf->compression & /* Look for no mask */ + (NITF_IMAGE_IO_COMPRESSION_NM + | NITF_IMAGE_IO_COMPRESSION_M1 + | NITF_IMAGE_IO_COMPRESSION_M3 + | NITF_IMAGE_IO_COMPRESSION_M4 + | NITF_IMAGE_IO_COMPRESSION_M5 + | NITF_IMAGE_IO_COMPRESSION_M8)) == 0 /* No masks */ ) + return NITF_FAILURE; + + *imageDataOffset = initf->maskHeader.imageDataOffset; + *blockRecordLength = initf->maskHeader.blockRecordLength; + *padRecordLength = initf->maskHeader.padRecordLength; + *padPixelValueLength = initf->maskHeader.padPixelValueLength; + *padValue = initf->pixel.pad; + *blockMask = initf->blockMask; + *padMask = initf->padMask; + + return NITF_SUCCESS; +} + diff --git a/modules/c/nitf/source/ImageReader.c b/modules/c/nitf/source/ImageReader.c new file mode 100644 index 000000000..a3298de4d --- /dev/null +++ b/modules/c/nitf/source/ImageReader.c @@ -0,0 +1,101 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/ImageReader.h" + +NITFAPI(nitf_BlockingInfo *) +nitf_ImageReader_getBlockingInfo(nitf_ImageReader * imageReader, + nitf_Error * error) +{ + return nitf_ImageIO_getBlockingInfo(imageReader->imageDeblocker, + imageReader->input, error); +} + + +NITFAPI(NITF_BOOL) nitf_ImageReader_read(nitf_ImageReader * imageReader, + nitf_SubWindow * subWindow, + nitf_Uint8 ** user, + int *padded, nitf_Error * error) +{ + return (NITF_BOOL) nitf_ImageIO_read(imageReader->imageDeblocker, + imageReader->input, + subWindow, user, padded, error); +} + +NITFAPI(nitf_Uint8*) nitf_ImageReader_readBlock(nitf_ImageReader * imageReader, + nitf_Uint32 blockNumber, + nitf_Uint64* blockSize, + nitf_Error * error) +{ + if(!imageReader->directBlockRead) + { + if(!nitf_ImageIO_setupDirectBlockRead(imageReader->imageDeblocker, + imageReader->input, + 1, + error)) + return NULL; + + imageReader->directBlockRead = 1; + } + + return nitf_ImageIO_readBlockDirect(imageReader->imageDeblocker, + imageReader->input, + blockNumber, + blockSize, + error); +} + +NITFAPI(void) nitf_ImageReader_destruct(nitf_ImageReader ** imageReader) +{ + if (*imageReader) + { + if ((void *) (*imageReader)->imageDeblocker != NULL) + { + /* + MANY PROBLEMS HERE. Solution is that destructor is + part of callback arena, or is deleted by ImageIO. + Problem one, getting out the IC at this point. + Problem two, getting the decompressor back from the struct + nitf_DecompressionInterface* decompIface = + (void*)(*segment)->imageIO->decompressor; + if (decompIface) + { + nitf_Error error; + if (!destroyDecompIface(&decompIface, error)) + nitf_Error_print(error, + "Unsuccessful decompressor destruction", + stderr); + } + */ + nitf_ImageIO_destruct(&(*imageReader)->imageDeblocker); + } + /*nitf_IOHandle_close((*imageReader)->inputHandle); */ + NITF_FREE(*imageReader); + *imageReader = NULL; + } +} + +NITFPROT(void) nitf_ImageReader_setReadCaching(nitf_ImageReader * iReader) +{ + nitf_ImageIO_setReadCaching(iReader->imageDeblocker); + return; +} diff --git a/modules/c/nitf/source/ImageSegment.c b/modules/c/nitf/source/ImageSegment.c new file mode 100644 index 000000000..69e17ae9b --- /dev/null +++ b/modules/c/nitf/source/ImageSegment.c @@ -0,0 +1,122 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/ImageSegment.h" +/* +NITFPRIV(nitf_DecompressionInterface*) getDecompIface(const char* comp, + int* bad, + nitf_Error* error); + +NITFPRIV(int) destroyDecompIface(nitf_DecompressionInterface** decompIface, + const char* comp, + nitf_Error* error); +*/ + +NITFAPI(nitf_ImageSegment *) nitf_ImageSegment_construct(nitf_Error * + error) +{ + nitf_ImageSegment *segment = + (nitf_ImageSegment *) NITF_MALLOC(sizeof(nitf_ImageSegment)); + + if (!segment) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + return NULL; + } + + /* This object gets created NOW */ + segment->subheader = NULL; + + /* The image offset in the file */ + segment->imageOffset = 0; + /* The image end (offset + length image) */ + segment->imageEnd = 0; + segment->subheader = nitf_ImageSubheader_construct(error); + if (!segment->subheader) + { + nitf_ImageSegment_destruct(&segment); + return NULL; + } + /* Yes! We have a success */ + return segment; +} + + +NITFAPI(nitf_ImageSegment *) nitf_ImageSegment_clone(nitf_ImageSegment * + source, + nitf_Error * error) +{ + nitf_ImageSegment *segment = NULL; + + if (source) + { + segment = + (nitf_ImageSegment *) NITF_MALLOC(sizeof(nitf_ImageSegment)); + + if (!segment) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + return NULL; + } + /* Just in case we self-destruct */ + segment->subheader = NULL; + + /* The image offset in the file */ + segment->imageOffset = source->imageOffset; + /* The image end (offset + length image) */ + segment->imageEnd = source->imageEnd; + segment->subheader = + nitf_ImageSubheader_clone(source->subheader, error); + if (!segment->subheader) + { + nitf_ImageSegment_destruct(&segment); + return NULL; + } + } + else + { + nitf_Error_initf(error, + NITF_CTXT, + NITF_ERR_INVALID_OBJECT, + "Trying to clone NULL pointer"); + } + /* Yes! We have a success */ + return segment; +} + + +NITFAPI(void) nitf_ImageSegment_destruct(nitf_ImageSegment ** segment) +{ + if (*segment) + { + if ((*segment)->subheader) + { + /* Destroy subheader info */ + nitf_ImageSubheader_destruct(&(*segment)->subheader); + } + } + NITF_FREE(*segment); + *segment = NULL; +} + diff --git a/modules/c/nitf/source/ImageSource.c b/modules/c/nitf/source/ImageSource.c new file mode 100644 index 000000000..7c5f8084f --- /dev/null +++ b/modules/c/nitf/source/ImageSource.c @@ -0,0 +1,93 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/ImageSource.h" + +NITFAPI(nitf_ImageSource *) nitf_ImageSource_construct(nitf_Error * error) +{ + nitf_ImageSource *imageSource = + (nitf_ImageSource *) NITF_MALLOC(sizeof(nitf_ImageSource)); + if (!imageSource) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + return NULL; + } + imageSource->bandSources = nitf_List_construct(error); + if (!imageSource->bandSources) + { + NITF_FREE(imageSource); + return NULL; + } + imageSource->size = 0; + return imageSource; +} + + +NITFAPI(void) nitf_ImageSource_destruct(nitf_ImageSource ** imageSource) +{ + if (*imageSource) + { + nitf_List *l = (*imageSource)->bandSources; + while (!nitf_List_isEmpty(l)) + { + nitf_BandSource *bandSource = + (nitf_BandSource *) nitf_List_popFront(l); + nitf_BandSource_destruct(&bandSource); + } + nitf_List_destruct(&l); + NITF_FREE(*imageSource); + *imageSource = NULL; + } +} + + +NITFAPI(NITF_BOOL) +nitf_ImageSource_addBand(nitf_ImageSource * imageSource, + nitf_BandSource * bandSource, nitf_Error * error) +{ + if (!nitf_List_pushBack(imageSource->bandSources, bandSource, error)) + return NITF_FAILURE; + ++imageSource->size; + return NITF_SUCCESS; +} + + +NITFAPI(nitf_BandSource *) +nitf_ImageSource_getBand(nitf_ImageSource * imageSource, + int n, nitf_Error * error) +{ + int i = 1; + nitf_ListIterator it; + if (n < 0 || n >= imageSource->size) + { + nitf_Error_init(error, + "Error: band out of range", + NITF_CTXT, NITF_ERR_INVALID_OBJECT); + return NULL; + } + it = nitf_List_begin(imageSource->bandSources); + + for (; i <= n; i++) + nitf_ListIterator_increment(&it); + return (nitf_BandSource *) nitf_ListIterator_get(&it); +} diff --git a/modules/c/nitf/source/ImageSubheader.c b/modules/c/nitf/source/ImageSubheader.c new file mode 100644 index 000000000..8925b5ef4 --- /dev/null +++ b/modules/c/nitf/source/ImageSubheader.c @@ -0,0 +1,1214 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/ImageSubheader.h" + +#define _NITF_CONSTRUCT_FIELD(OWNER, ID, TYPE) \ + OWNER->ID = nitf_Field_construct(ID##_SZ, TYPE, error); \ + if (!OWNER->ID) goto CATCH_ERROR; + +#define _NITF_CLONE_FIELD(DEST, SOURCE, ID) \ + DEST->ID = nitf_Field_clone(SOURCE->ID, error); \ + if (!DEST->ID) goto CATCH_ERROR; + +#define _NITF_DESTRUCT_FIELD(OWNER, ID) \ + if (OWNER->ID) nitf_Field_destruct(OWNER->ID); + +#define _NITF_BLOCK_DIM_MAX (8192) +#define _NITF_BLOCK_DEFAULT_MAX (1024) +#define _NITF_BLOCK_DEFAULT_MIN (1024) + +NITFPRIV(void) +nitf_ImageSubheader_computeBlockingImpl(nitf_Uint32 numDims, + nitf_Uint32* numDimsPerBlock, + nitf_Uint32* numBlocksPerDim) +{ + /* for 2500C - if > 8192, then NROWS/NCOLS specifies NPPBV/NPPBH */ + if (*numDimsPerBlock > _NITF_BLOCK_DIM_MAX) + { + *numDimsPerBlock = 0; + } + + if (*numDimsPerBlock != 0) /* 2500B */ + { + *numBlocksPerDim = numDims / *numDimsPerBlock; + + if (numDims % *numDimsPerBlock != 0) + { + /* Residual, need one more block */ + *numBlocksPerDim += 1; + } + } + else + { + *numBlocksPerDim = 1; /* 2500C */ + } +} + +NITFAPI(nitf_ImageSubheader *) +nitf_ImageSubheader_construct(nitf_Error * error) +{ + /* Start by allocating the header */ + nitf_ImageSubheader *subhdr = (nitf_ImageSubheader *) + NITF_MALLOC(sizeof(nitf_ImageSubheader)); + + /* Return now if we have a problem above */ + if (!subhdr) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + + return NULL; + } + + subhdr->securityGroup = NULL; + subhdr->imageComments = NULL; + + subhdr->userDefinedSection = NULL; + subhdr->extendedSection = NULL; + + subhdr->securityGroup = nitf_FileSecurity_construct(error); + if (!subhdr->securityGroup) + goto CATCH_ERROR; + + subhdr->imageComments = nitf_List_construct(error); + if (!subhdr->imageComments) + goto CATCH_ERROR; + + + _NITF_CONSTRUCT_FIELD(subhdr, NITF_IM, NITF_BCS_A); + _NITF_CONSTRUCT_FIELD(subhdr, NITF_IID1, NITF_BCS_A); + _NITF_CONSTRUCT_FIELD(subhdr, NITF_IDATIM, NITF_BCS_A); + _NITF_CONSTRUCT_FIELD(subhdr, NITF_TGTID, NITF_BCS_A); + _NITF_CONSTRUCT_FIELD(subhdr, NITF_IID2, NITF_BCS_A); + _NITF_CONSTRUCT_FIELD(subhdr, NITF_ISCLAS, NITF_BCS_A); + + _NITF_CONSTRUCT_FIELD(subhdr, NITF_ENCRYP, NITF_BCS_A); + _NITF_CONSTRUCT_FIELD(subhdr, NITF_ISORCE, NITF_BCS_A); + + _NITF_CONSTRUCT_FIELD(subhdr, NITF_NROWS, NITF_BCS_N); + _NITF_CONSTRUCT_FIELD(subhdr, NITF_NCOLS, NITF_BCS_N); + + _NITF_CONSTRUCT_FIELD(subhdr, NITF_PVTYPE, NITF_BCS_A); + _NITF_CONSTRUCT_FIELD(subhdr, NITF_IREP, NITF_BCS_A); + _NITF_CONSTRUCT_FIELD(subhdr, NITF_ICAT, NITF_BCS_A); + + _NITF_CONSTRUCT_FIELD(subhdr, NITF_ABPP, NITF_BCS_N); + + _NITF_CONSTRUCT_FIELD(subhdr, NITF_PJUST, NITF_BCS_A); + _NITF_CONSTRUCT_FIELD(subhdr, NITF_ICORDS, NITF_BCS_A); + _NITF_CONSTRUCT_FIELD(subhdr, NITF_IGEOLO, NITF_BCS_A); + + _NITF_CONSTRUCT_FIELD(subhdr, NITF_NICOM, NITF_BCS_N); + + _NITF_CONSTRUCT_FIELD(subhdr, NITF_IC, NITF_BCS_A); + _NITF_CONSTRUCT_FIELD(subhdr, NITF_COMRAT, NITF_BCS_A); + + _NITF_CONSTRUCT_FIELD(subhdr, NITF_NBANDS, NITF_BCS_N); + _NITF_CONSTRUCT_FIELD(subhdr, NITF_XBANDS, NITF_BCS_N); + + subhdr->bandInfo = NULL; + + _NITF_CONSTRUCT_FIELD(subhdr, NITF_ISYNC, NITF_BCS_N); + _NITF_CONSTRUCT_FIELD(subhdr, NITF_IMODE, NITF_BCS_A); + + _NITF_CONSTRUCT_FIELD(subhdr, NITF_NBPR, NITF_BCS_N); + _NITF_CONSTRUCT_FIELD(subhdr, NITF_NBPC, NITF_BCS_N); + _NITF_CONSTRUCT_FIELD(subhdr, NITF_NPPBH, NITF_BCS_N); + _NITF_CONSTRUCT_FIELD(subhdr, NITF_NPPBV, NITF_BCS_N); + _NITF_CONSTRUCT_FIELD(subhdr, NITF_NBPP, NITF_BCS_N); + + _NITF_CONSTRUCT_FIELD(subhdr, NITF_IDLVL, NITF_BCS_N); + _NITF_CONSTRUCT_FIELD(subhdr, NITF_IALVL, NITF_BCS_N); + _NITF_CONSTRUCT_FIELD(subhdr, NITF_ILOC, NITF_BCS_N); + _NITF_CONSTRUCT_FIELD(subhdr, NITF_IMAG, NITF_BCS_A); + + _NITF_CONSTRUCT_FIELD(subhdr, NITF_UDIDL, NITF_BCS_N); + _NITF_CONSTRUCT_FIELD(subhdr, NITF_UDOFL, NITF_BCS_N); + _NITF_CONSTRUCT_FIELD(subhdr, NITF_IXSHDL, NITF_BCS_N); + _NITF_CONSTRUCT_FIELD(subhdr, NITF_IXSOFL, NITF_BCS_N); + + subhdr->userDefinedSection = nitf_Extensions_construct(error); + if (!subhdr->userDefinedSection) + goto CATCH_ERROR; + subhdr->extendedSection = nitf_Extensions_construct(error); + if (!subhdr->extendedSection) + goto CATCH_ERROR; + + return subhdr; + +CATCH_ERROR: + nitf_ImageSubheader_destruct(&subhdr); + return NULL; +} + + +NITFAPI(nitf_ImageSubheader *) +nitf_ImageSubheader_clone(nitf_ImageSubheader * source, nitf_Error * error) +{ + nitf_Uint32 nbands, i; + + nitf_ImageSubheader *subhdr = NULL; + if (source) + { + subhdr = + (nitf_ImageSubheader *) + NITF_MALLOC(sizeof(nitf_ImageSubheader)); + if (!subhdr) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + return NULL; + } + + subhdr->securityGroup = + nitf_FileSecurity_clone(source->securityGroup, error); + if (!subhdr->securityGroup) + goto CATCH_ERROR; + + subhdr->imageComments = nitf_List_clone(source->imageComments, + (NITF_DATA_ITEM_CLONE) nitf_Field_clone, error); + if (!subhdr->imageComments) + goto CATCH_ERROR; + + /* Copy some fields */ + _NITF_CLONE_FIELD(subhdr, source, NITF_IM); + _NITF_CLONE_FIELD(subhdr, source, NITF_IID1); + _NITF_CLONE_FIELD(subhdr, source, NITF_IDATIM); + _NITF_CLONE_FIELD(subhdr, source, NITF_TGTID); + _NITF_CLONE_FIELD(subhdr, source, NITF_IID2); + _NITF_CLONE_FIELD(subhdr, source, NITF_ISCLAS); + + _NITF_CLONE_FIELD(subhdr, source, NITF_ENCRYP); + _NITF_CLONE_FIELD(subhdr, source, NITF_ISORCE); + + /* And some values (ints in this case) */ + _NITF_CLONE_FIELD(subhdr, source, NITF_NROWS); + _NITF_CLONE_FIELD(subhdr, source, NITF_NCOLS); + + /* And some more fields */ + _NITF_CLONE_FIELD(subhdr, source, NITF_PVTYPE); + _NITF_CLONE_FIELD(subhdr, source, NITF_IREP); + _NITF_CLONE_FIELD(subhdr, source, NITF_ICAT); + + /* Even more fields */ + _NITF_CLONE_FIELD(subhdr, source, NITF_PJUST); + _NITF_CLONE_FIELD(subhdr, source, NITF_ICORDS); + _NITF_CLONE_FIELD(subhdr, source, NITF_IGEOLO); + + _NITF_CLONE_FIELD(subhdr, source, NITF_NICOM); + _NITF_CLONE_FIELD(subhdr, source, NITF_IC); + _NITF_CLONE_FIELD(subhdr, source, NITF_COMRAT); + + _NITF_CLONE_FIELD(subhdr, source, NITF_NBANDS); + _NITF_CLONE_FIELD(subhdr, source, NITF_XBANDS); + + subhdr->bandInfo = NULL; + + { + /* Scope this locally */ + nbands = nitf_ImageSubheader_getBandCount(source, error); + if (nbands > 0 && nbands != NITF_INVALID_BAND_COUNT) + { + subhdr->bandInfo = + (nitf_BandInfo **) NITF_MALLOC(sizeof(nitf_BandInfo *) + * nbands); + if (!subhdr->bandInfo) + { + nitf_ImageSubheader_destruct(&subhdr); + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + return NULL; + + } + } + if (nbands != NITF_INVALID_BAND_COUNT) + for (i = 0; i < nbands; i++) + subhdr->bandInfo[i] = + nitf_BandInfo_clone(source->bandInfo[i], error); + } + + _NITF_CLONE_FIELD(subhdr, source, NITF_ISYNC); + _NITF_CLONE_FIELD(subhdr, source, NITF_IMODE); + + _NITF_CLONE_FIELD(subhdr, source, NITF_ABPP); + _NITF_CLONE_FIELD(subhdr, source, NITF_NBPR); + _NITF_CLONE_FIELD(subhdr, source, NITF_NBPC); + _NITF_CLONE_FIELD(subhdr, source, NITF_NPPBH); + _NITF_CLONE_FIELD(subhdr, source, NITF_NPPBV); + _NITF_CLONE_FIELD(subhdr, source, NITF_NBPP); + + _NITF_CLONE_FIELD(subhdr, source, NITF_IDLVL); + _NITF_CLONE_FIELD(subhdr, source, NITF_IALVL); + _NITF_CLONE_FIELD(subhdr, source, NITF_ILOC); + _NITF_CLONE_FIELD(subhdr, source, NITF_IMAG); + + _NITF_CLONE_FIELD(subhdr, source, NITF_UDIDL); + _NITF_CLONE_FIELD(subhdr, source, NITF_UDOFL); + _NITF_CLONE_FIELD(subhdr, source, NITF_IXSHDL); + _NITF_CLONE_FIELD(subhdr, source, NITF_IXSOFL); + + /* init these to NULL for safety */ + subhdr->userDefinedSection = NULL; + subhdr->extendedSection = NULL; + + if (source->userDefinedSection) + { + + subhdr->userDefinedSection = + nitf_Extensions_clone(source->userDefinedSection, error); + + if (!subhdr->userDefinedSection) + goto CATCH_ERROR; + } + + if (source->extendedSection) + { + subhdr->extendedSection = + nitf_Extensions_clone(source->extendedSection, error); + + if (!subhdr->extendedSection) + goto CATCH_ERROR; + } + + return subhdr; + } + +CATCH_ERROR: + nitf_ImageSubheader_destruct(&subhdr); + return NULL; + +} + +NITFAPI(nitf_CornersType) +nitf_ImageSubheader_getCornersType(nitf_ImageSubheader* subheader) +{ + nitf_CornersType type = NITF_CORNERS_UNKNOWN; + switch (subheader->NITF_ICORDS->raw[0]) + { + case 'U': + type = NITF_CORNERS_UTM; + break; + + case 'N': + type = NITF_CORNERS_UTM_UPS_N; + break; + + case 'S': + type = NITF_CORNERS_UTM_UPS_S; + break; + + case 'D': + type = NITF_CORNERS_DECIMAL; + break; + + case 'G': + type = NITF_CORNERS_GEO; + break; + + } + return type; +} + +NITFAPI(NITF_BOOL) +nitf_ImageSubheader_setCornersFromLatLons(nitf_ImageSubheader* subheader, + nitf_CornersType type, + double corners[4][2], + nitf_Error* error) +{ + + char cornerRep = nitf_Utils_cornersTypeAsCoordRep(type); + char *igeolo = subheader->NITF_IGEOLO->raw; + unsigned int i = 0; + unsigned int where = 0; + + if (type == NITF_CORNERS_GEO) + { + + for (; i < 4; i++) + { + nitf_Utils_decimalLatToGeoCharArray(corners[i][0], &igeolo[where]); + where += 7; + nitf_Utils_decimalLonToGeoCharArray(corners[i][1], &igeolo[where]); + where += 8; + } + + } + else if (type == NITF_CORNERS_DECIMAL) + { + for (; i < 4; i++) + { + nitf_Utils_decimalLatToCharArray(corners[i][0], &igeolo[where]); + where += 7; + nitf_Utils_decimalLonToCharArray(corners[i][1], &igeolo[where]); + where += 8; + } + } + else + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_INVALID_PARAMETER, + "Can only support IGEOLO 'D' or 'G' for this operation. Found %c", + cornerRep); + return NITF_FAILURE; + } + + /* Go ahead and set ICORDS */ + subheader->NITF_ICORDS->raw[0] = cornerRep; + return NITF_SUCCESS; + +} + + +NITFAPI(NITF_BOOL) +nitf_ImageSubheader_getCornersAsLatLons(nitf_ImageSubheader* subheader, + double corners[4][2], + nitf_Error *error) +{ + nitf_CornersType type = nitf_ImageSubheader_getCornersType(subheader); + char *igeolo = subheader->NITF_IGEOLO->raw; + unsigned int i = 0; + unsigned int where = 0; + + if (type == NITF_CORNERS_GEO) + { + + for (; i < 4; i++) + { + int d, m; + double s; + char lat[8]; + char lon[9]; + lat[7] = 0; + lon[8] = 0; + memcpy(lat, &igeolo[where], 7); + where += 7; + if (!nitf_Utils_parseGeographicString(lat, &d, &m, &s, error)) + return NITF_FAILURE; + + corners[i][0] = nitf_Utils_geographicToDecimal(d, m, s); + + memcpy(lon, &igeolo[where], 8); + where += 8; + + if (!nitf_Utils_parseGeographicString(lon, &d, &m, &s, error)) + return NITF_FAILURE; + + corners[i][1] = nitf_Utils_geographicToDecimal(d, m, s); + + /* Now I need to get them as decimal */ + } + + } + else if (type == NITF_CORNERS_DECIMAL) + { + for (; i < 4; i++) + { + char lat[8]; + char lon[9]; + lat[7] = 0; + lon[8] = 0; + memcpy(lat, &igeolo[where], 7); + where += 7; + if (!nitf_Utils_parseDecimalString(lat, &(corners[i][0]), error)) + return NITF_FAILURE; + + memcpy(lon, &igeolo[where], 8); + where += 8; + + if (!nitf_Utils_parseDecimalString(lon, &(corners[i][1]), error)) + return NITF_FAILURE; + + } + } + else + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_INVALID_PARAMETER, + "Can only support IGEOLO 'D' or 'G' for this operation. Found %c", + subheader->NITF_ICORDS->raw[0]); + return NITF_FAILURE; + } + return NITF_SUCCESS; +} + +NITFAPI(void) nitf_ImageSubheader_destruct(nitf_ImageSubheader ** subhdr) +{ + nitf_Error e; + nitf_Uint32 nbands, i; + + if (!*subhdr) + return; + + if ((*subhdr)->userDefinedSection) + { + nitf_Extensions_destruct(&(*subhdr)->userDefinedSection); + } + if ((*subhdr)->extendedSection) + { + nitf_Extensions_destruct(&(*subhdr)->extendedSection); + } + if ((*subhdr)->securityGroup) + { + nitf_FileSecurity_destruct(&(*subhdr)->securityGroup); + (*subhdr)->securityGroup = NULL; + } + if ((*subhdr)->imageComments) + { + nitf_ListIterator iter, end; + iter = nitf_List_begin((*subhdr)->imageComments); + end = nitf_List_end((*subhdr)->imageComments); + while (nitf_ListIterator_notEqualTo(&iter, &end)) + { + nitf_Field* field = (nitf_Field*) nitf_List_remove( + (*subhdr)->imageComments, &iter); + if (field) nitf_Field_destruct(&field); + } + nitf_List_destruct(&(*subhdr)->imageComments); + (*subhdr)->imageComments = NULL; + } + if ((*subhdr)->bandInfo) + { + nbands = nitf_ImageSubheader_getBandCount((*subhdr), &e); + + /*nbands = bands + xBands; */ + if (nbands != NITF_INVALID_BAND_COUNT) + for (i = 0; i < nbands; i++) + nitf_BandInfo_destruct(&((*subhdr)->bandInfo[i])); + NITF_FREE((*subhdr)->bandInfo); + } + + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_IM); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_IID1); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_IDATIM); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_TGTID); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_IID2); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_ISCLAS); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_ENCRYP); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_ISORCE); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_NROWS); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_NCOLS); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_PVTYPE); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_IREP); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_ICAT); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_ABPP); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_PJUST); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_ICORDS); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_IGEOLO); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_NICOM); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_IC); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_COMRAT); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_NBANDS); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_XBANDS); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_ISYNC); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_IMODE); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_NBPR); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_NBPC); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_NPPBH); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_NPPBV); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_NBPP); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_IDLVL); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_IALVL); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_ILOC); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_IMAG); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_UDIDL); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_UDOFL); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_IXSHDL); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_IXSOFL); + + NITF_FREE(*subhdr); + *subhdr = NULL; + +} + + +NITFAPI(NITF_BOOL) +nitf_ImageSubheader_setPixelInformation(nitf_ImageSubheader * subhdr, + const char *pvtype, nitf_Uint32 nbpp, + nitf_Uint32 abpp, + const char *justification, + const char *irep, + const char *icat, nitf_Uint32 bandCount, + nitf_BandInfo ** bands, + nitf_Error * error) +{ + nitf_Uint32 nbands; /* The NBANDS value */ + nitf_Uint32 xbands; /* The XBANDS value */ + nitf_Uint32 bandCountOld; /* The current band count */ + + /* Get currrent band count (need to free old bands) */ + + bandCountOld = nitf_ImageSubheader_getBandCount(subhdr, error); + if (bandCountOld == NITF_INVALID_BAND_COUNT) + return (NITF_FAILURE); + + if (bandCount > 9) + { + nbands = 0; + xbands = bandCount; + } + else + { + nbands = bandCount; + xbands = 0; + } + + /* + * Set the fields. There can be errors if the string lengths are too long. + */ + + if (!nitf_Field_setString(subhdr->NITF_PVTYPE, pvtype, error)) + return (NITF_FAILURE); + + if (!nitf_Field_setString(subhdr->NITF_PJUST, justification, error)) + return (NITF_FAILURE); + + if (!nitf_Field_setUint32(subhdr->NITF_NBPP, nbpp, error)) + return (NITF_FAILURE); + + if (!nitf_Field_setUint32(subhdr->NITF_ABPP, abpp, error)) + return (NITF_FAILURE); + + if (!nitf_Field_setUint32(subhdr->NITF_NBANDS, nbands, error)) + return (NITF_FAILURE); + + if (!nitf_Field_setUint32(subhdr->NITF_XBANDS, xbands, error)) + return (NITF_FAILURE); + + if (!nitf_Field_setString(subhdr->NITF_IREP, irep, error)) + return (NITF_FAILURE); + + if (!nitf_Field_setString(subhdr->NITF_ICAT, icat, error)) + return (NITF_FAILURE); + + /* Free existing bands */ + + if (subhdr->bandInfo != NULL) /* Free existing band data */ + { + nitf_Uint32 i; + + for (i = 0; i < bandCountOld; i++) + { + nitf_BandInfo_destruct(&(subhdr->bandInfo[i])); + } + NITF_FREE(subhdr->bandInfo); + } + subhdr->bandInfo = bands; + + return (NITF_SUCCESS); +} + + +NITFAPI(nitf_Uint32) nitf_ImageSubheader_getBandCount(nitf_ImageSubheader * + subhdr, + nitf_Error * error) +{ + nitf_Uint32 nbands; /* The NBANDS field */ + nitf_Uint32 xbands; /* The XBANDS field */ + nitf_Uint32 bandCount; /* The result */ + + /* Get the required subheader values */ + + if (!nitf_Field_get(subhdr->NITF_NBANDS, (NITF_DATA *) (&nbands), + NITF_CONV_INT, NITF_INT32_SZ, error)) + return NITF_INVALID_BAND_COUNT; + if (!nitf_Field_get(subhdr->NITF_XBANDS, (NITF_DATA *) (&xbands), + NITF_CONV_INT, NITF_INT32_SZ, error)) + return NITF_INVALID_BAND_COUNT; + + /* The count is nbands unless it is 0. */ + + if (nbands != 0) + { + bandCount = nbands; + if (xbands != 0) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_INVALID_PARAMETER, + "NBANDS (%d) and XBANDS (%d) cannot both be non-zero", + nbands, xbands); + return NITF_INVALID_BAND_COUNT; + } + } + else + bandCount = xbands; + + if (bandCount > NITF_MAX_BAND_COUNT) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_INVALID_PARAMETER, + "Invalid band count NBANDS is %d and XBANDS is %d", + nbands, xbands); + } + + return bandCount; +} + + +NITFAPI(nitf_BandInfo *) +nitf_ImageSubheader_getBandInfo(nitf_ImageSubheader * subhdr, + nitf_Uint32 band, nitf_Error * error) +{ + nitf_Uint32 bandCount; /* The band count for the range check */ + + /* Range check */ + + bandCount = nitf_ImageSubheader_getBandCount(subhdr, error); + if (bandCount == NITF_INVALID_BAND_COUNT) + return (NULL); + + if (bandCount <= band) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_INVALID_PARAMETER, + "Band index %d is out of range (band count == %d)", + band, bandCount); + + return (NULL); + } + + return (subhdr->bandInfo[band]); +} + + +NITFAPI(NITF_BOOL) nitf_ImageSubheader_createBands(nitf_ImageSubheader * + subhdr, + nitf_Uint32 numBands, + nitf_Error * error) +{ + nitf_BandInfo *bandInfo = NULL; /* temp BandInfo object */ + nitf_BandInfo **infos = NULL; /* new BandInfo array */ + nitf_Uint32 curBandCount; /* current band count */ + nitf_Uint32 totalBandCount; /* total band count */ + int i; + char buf[256]; /* temp buf */ + + /* first, get the current number of bands */ + curBandCount = nitf_ImageSubheader_getBandCount(subhdr, error); + /* check to see if this is a NEW subheader with no bands yet */ + if (curBandCount == NITF_INVALID_BAND_COUNT) + curBandCount = 0; + totalBandCount = curBandCount + numBands; + + /* check if invalid values */ + if (totalBandCount > NITF_MAX_BAND_COUNT || numBands <= 0) + { + /* throw an error */ + nitf_Error_init(error, + "Invalid total Band Count, or invalid numBands", + NITF_CTXT, NITF_ERR_INVALID_PARAMETER); + goto CATCH_ERROR; + } + + /* set the new array */ + infos = + (nitf_BandInfo **) NITF_MALLOC(sizeof(nitf_BandInfo *) * + (totalBandCount)); + if (!infos) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + goto CATCH_ERROR; + } + + for (i = 0; subhdr->bandInfo && i < curBandCount; ++i) + { + /* copy over old pointers -- assuming old array == curBandCount! */ + infos[i] = subhdr->bandInfo[i]; + } + + /* now, create the new infos */ + for (i = 0; i < numBands; ++i) + { + bandInfo = nitf_BandInfo_construct(error); + if (!bandInfo) + { + goto CATCH_ERROR; + } + /* set it in the new array */ + infos[curBandCount + i] = bandInfo; + } + + /* set the new values into the ImageSubheader fields */ + NITF_SNPRINTF(buf, 256, "%.*d", NITF_NBANDS_SZ, + (totalBandCount > 9 ? 0 : totalBandCount)); + nitf_Field_setRawData(subhdr->numImageBands, buf, NITF_NBANDS_SZ, + error); + + NITF_SNPRINTF(buf, 256, "%.*d", NITF_XBANDS_SZ, + (totalBandCount > 9 ? totalBandCount : 0)); + nitf_Field_setRawData(subhdr->numMultispectralImageBands, buf, + NITF_XBANDS_SZ, error); + + /* delete old array, and set equal to the new one */ + if (subhdr->bandInfo) + NITF_FREE(subhdr->bandInfo); + subhdr->bandInfo = infos; + + /* ok! */ + return NITF_SUCCESS; + +CATCH_ERROR: + if (bandInfo) + nitf_BandInfo_destruct(&bandInfo); + if (infos) + NITF_FREE(infos); + return NITF_FAILURE; +} + + + +NITFAPI(NITF_BOOL) nitf_ImageSubheader_removeBand( + nitf_ImageSubheader * subhdr, + nitf_Uint32 index, + nitf_Error * error +) +{ + nitf_BandInfo *bandInfo = NULL; /* temp BandInfo object */ + nitf_BandInfo **infos = NULL; /* new BandInfo array */ + nitf_Uint32 curBandCount; /* current band count */ + int i; + char buf[256]; /* temp buf */ + + /* first, get the current number of bands */ + curBandCount = nitf_ImageSubheader_getBandCount(subhdr, error); + /* check to see if this is a NEW subheader with no bands yet */ + if (curBandCount == NITF_INVALID_BAND_COUNT || index < 0 || + index >= curBandCount) + { + nitf_Error_init(error, "Invalid band index", + NITF_CTXT, NITF_ERR_INVALID_PARAMETER); + goto CATCH_ERROR; + } + + /* decrement the band count */ + curBandCount--; + + /* set the new values into the ImageSubheader fields */ + NITF_SNPRINTF(buf, 256, "%.*d", NITF_NBANDS_SZ, + (curBandCount > 9 ? 0 : curBandCount)); + nitf_Field_setRawData(subhdr->numImageBands, buf, NITF_NBANDS_SZ, + error); + NITF_SNPRINTF(buf, 256, "%.*d", NITF_XBANDS_SZ, + (curBandCount > 9 ? curBandCount : 0)); + nitf_Field_setRawData(subhdr->numMultispectralImageBands, buf, + NITF_XBANDS_SZ, error); + + /* set the new array */ + infos = + (nitf_BandInfo **) NITF_MALLOC(sizeof(nitf_BandInfo *) * + (curBandCount)); + if (!infos) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + goto CATCH_ERROR; + } + + for (i = 0; subhdr->bandInfo && i < index; ++i) + { + infos[i] = subhdr->bandInfo[i]; + } + for (i = index; subhdr->bandInfo && i < curBandCount; ++i) + { + infos[i] = subhdr->bandInfo[i + 1]; + } + + /* delete old array, and set equal to the new one */ + if (subhdr->bandInfo) + { + /* delete the removed bandInfo */ + bandInfo = subhdr->bandInfo[index]; + nitf_BandInfo_destruct(&bandInfo); + NITF_FREE(subhdr->bandInfo); + } + subhdr->bandInfo = infos; + + return NITF_SUCCESS; + +CATCH_ERROR: + if (infos) + NITF_FREE(infos); + return NITF_FAILURE; +} + + +/* + * Select a block dimension size based on a dimension + * + * This function selects a block dimension (row or column length) given the + * supplied image dimension. It will select the largest length that is a + * multiple of four and an exact divisor of the block size between + * _NITF_BLOCK_DEFAULT_MIN and _NITF_BLOCK_DEFAULT_MAX. If none is found, it + * selects the one that produces the least pad. + * + * Note: This function is only called if the image dimension is larger than + * 8192 + */ + +NITFPRIV(nitf_Uint32) selectBlockSize(nitf_Uint32 size) +{ + nitf_Uint32 blockSize; /* Current block size */ + nitf_Uint32 blockSizeMin; /* Block size that give minimum pad */ + nitf_Uint32 padSize; /* Current pad size */ + nitf_Uint32 padSizeMin; /* Current minimum pad size */ + + nitf_Uint32 remainder; /* Remainder of size/blockSize */ + + /* Start at MAX and work backwards */ + + blockSize = _NITF_BLOCK_DEFAULT_MAX; + remainder = size % blockSize; + if (remainder == 0) + return (blockSize); + padSizeMin = blockSize - remainder; + blockSizeMin = blockSize; + + for (blockSize = _NITF_BLOCK_DEFAULT_MAX - 4; + blockSize >= _NITF_BLOCK_DEFAULT_MIN; blockSize -= 4) + { + remainder = size % blockSize; + if (remainder == 0) + return (blockSize); + + padSize = blockSize - remainder; + if (padSize < padSizeMin) + { + padSizeMin = padSize; + blockSizeMin = blockSize; + } + } + return (blockSizeMin); +} + + + +NITFAPI(NITF_BOOL) nitf_ImageSubheader_getDimensions(nitf_ImageSubheader * + subhdr, + nitf_Uint32 * numRows, + nitf_Uint32 * numCols, + nitf_Error * error) +{ + + if (!nitf_Field_get(subhdr->NITF_NROWS, + (NITF_DATA *) numRows, NITF_CONV_INT, + NITF_INT32_SZ, error)) + return (NITF_FAILURE); + + if (!nitf_Field_get(subhdr->NITF_NCOLS, + (NITF_DATA *) numCols, NITF_CONV_INT, + NITF_INT32_SZ, error)) + return (NITF_FAILURE); + + return (NITF_SUCCESS); +} + + +NITFAPI(NITF_BOOL) nitf_ImageSubheader_getBlocking(nitf_ImageSubheader * + subhdr, + nitf_Uint32 * numRows, + nitf_Uint32 * numCols, + nitf_Uint32 * + numRowsPerBlock, + nitf_Uint32 * + numColsPerBlock, + nitf_Uint32 * + numBlocksPerRow, + nitf_Uint32 * + numBlocksPerCol, + char *imode, + nitf_Error * error) +{ + + if (!nitf_Field_get(subhdr->NITF_NROWS, + (NITF_DATA *) numRows, NITF_CONV_INT, + NITF_INT32_SZ, error)) + return (NITF_FAILURE); + + if (!nitf_Field_get(subhdr->NITF_NCOLS, + (NITF_DATA *) numCols, NITF_CONV_INT, + NITF_INT32_SZ, error)) + return (NITF_FAILURE); + + if (!nitf_Field_get(subhdr->NITF_NPPBV, + (NITF_DATA *) numRowsPerBlock, NITF_CONV_INT, + NITF_INT32_SZ, error)) + return (NITF_FAILURE); + + if (!nitf_Field_get(subhdr->NITF_NPPBH, + (NITF_DATA *) numColsPerBlock, NITF_CONV_INT, + NITF_INT32_SZ, error)) + return (NITF_FAILURE); + + if (!nitf_Field_get(subhdr->NITF_NBPR, + (NITF_DATA *) numBlocksPerRow, NITF_CONV_INT, + NITF_INT32_SZ, error)) + return (NITF_FAILURE); + + if (!nitf_Field_get(subhdr->NITF_NBPC, + (NITF_DATA *) numBlocksPerCol, NITF_CONV_INT, + NITF_INT32_SZ, error)) + return (NITF_FAILURE); + + if (!nitf_Field_get(subhdr->NITF_IMODE, + (NITF_DATA *) imode, NITF_CONV_STRING, + NITF_IMODE_SZ + 1, error)) + return (NITF_FAILURE); + nitf_Field_trimString(imode); + + return (NITF_SUCCESS); +} + + +NITFAPI(NITF_BOOL) nitf_ImageSubheader_getCompression(nitf_ImageSubheader * + subhdr, + char *imageCompression, + char *compressionRate, + nitf_Error * error) +{ + + if (!nitf_Field_get(subhdr->NITF_IC, + (NITF_DATA *) imageCompression, NITF_CONV_STRING, + NITF_IC_SZ + 1, error)) + return (NITF_FAILURE); + nitf_Field_trimString(imageCompression); + + if (!nitf_Field_get(subhdr->NITF_COMRAT, + (NITF_DATA *) compressionRate, NITF_CONV_STRING, + NITF_COMRAT_SZ + 1, error)) + return (NITF_FAILURE); + nitf_Field_trimString(compressionRate); + + return (NITF_SUCCESS); +} + + +NITFAPI(NITF_BOOL) nitf_ImageSubheader_setDimensions(nitf_ImageSubheader * + subhdr, + nitf_Uint32 numRows, + nitf_Uint32 numCols, + nitf_Error * error) +{ + nitf_Uint32 numRowsPerBlock; /* The number of rows/block */ + nitf_Uint32 numColsPerBlock; /* The number of columns/block */ + + if (numRows <= _NITF_BLOCK_DIM_MAX) + numRowsPerBlock = numRows; + else + numRowsPerBlock = selectBlockSize(numRows); + + if (numCols <= _NITF_BLOCK_DIM_MAX) + numColsPerBlock = numCols; + else + numColsPerBlock = selectBlockSize(numCols); + + return (nitf_ImageSubheader_setBlocking(subhdr, numRows, numCols, + numRowsPerBlock, + numColsPerBlock, "B", error)); +} + + +NITFAPI(void) +nitf_ImageSubheader_computeBlocking( + nitf_Uint32 numRows, + nitf_Uint32 numCols, + nitf_Uint32* numRowsPerBlock, + nitf_Uint32* numColsPerBlock, + nitf_Uint32* numBlocksPerCol, + nitf_Uint32* numBlocksPerRow) +{ + /* + The number of blocks per column is a backwards way of saying the number + of rows of blocks. So the numBlocksPerCol calculation involves row counts + and numBlocksPerRow calculation involves column counts + */ + nitf_ImageSubheader_computeBlockingImpl(numRows, + numRowsPerBlock, + numBlocksPerCol); + + nitf_ImageSubheader_computeBlockingImpl(numCols, + numColsPerBlock, + numBlocksPerRow); +} + +NITFAPI(NITF_BOOL) nitf_ImageSubheader_setBlocking(nitf_ImageSubheader *subhdr, + nitf_Uint32 numRows, + nitf_Uint32 numCols, + nitf_Uint32 numRowsPerBlock, + nitf_Uint32 numColsPerBlock, + const char *imode, + nitf_Error *error) +{ + nitf_Uint32 numBlocksPerRow; /* Number of blocks/row */ + nitf_Uint32 numBlocksPerCol; /* Number of blocks/column */ + + nitf_ImageSubheader_computeBlocking(numRows, + numCols, + &numRowsPerBlock, + &numColsPerBlock, + &numBlocksPerCol, + &numBlocksPerRow); + + if (!nitf_Field_setUint32(subhdr->NITF_NROWS, numRows, error)) + return (NITF_FAILURE); + + if (!nitf_Field_setUint32(subhdr->NITF_NCOLS, numCols, error)) + return (NITF_FAILURE); + + if (!nitf_Field_setUint32(subhdr->NITF_NPPBV, numRowsPerBlock, error)) + return (NITF_FAILURE); + + if (!nitf_Field_setUint32(subhdr->NITF_NPPBH, numColsPerBlock, error)) + return (NITF_FAILURE); + + if (!nitf_Field_setUint32(subhdr->NITF_NBPC, numBlocksPerCol, error)) + return (NITF_FAILURE); + + if (!nitf_Field_setUint32(subhdr->NITF_NBPR, numBlocksPerRow, error)) + return (NITF_FAILURE); + + if (!nitf_Field_setString(subhdr->NITF_IMODE, imode, error)) + return (NITF_FAILURE); + + return (NITF_SUCCESS); +} + + +NITFAPI(NITF_BOOL) nitf_ImageSubheader_setCompression(nitf_ImageSubheader *subhdr, + const char *imageCompression, + const char *compressionRate, + nitf_Error * error) +{ + if (!nitf_Field_setString(subhdr->NITF_IC, imageCompression, error)) + return (NITF_FAILURE); + + if (!nitf_Field_setString(subhdr->NITF_COMRAT, compressionRate, error)) + return (NITF_FAILURE); + + return (NITF_SUCCESS); +} + +NITFAPI(int) nitf_ImageSubheader_insertImageComment +( + nitf_ImageSubheader * subhdr, + const char *comment, + int position, + nitf_Error * error +) +{ + nitf_Uint32 numComments; + nitf_ListIterator iterPos; + nitf_Field* field = NULL; + char numCommentBuf[NITF_NICOM_SZ + 1]; + char commentBuf[NITF_ICOM_SZ + 1]; + int length; + + NITF_TRY_GET_UINT32(subhdr->numImageComments, &numComments, error); + /* in case there is bad info in numImageComments */ + numComments = numComments < 0 ? 0 : numComments; + + /* see if we can really add another one */ + if (numComments < 9) + { + /* check the position */ + if (position < 0 || position > numComments) + position = numComments; + + /* make the field */ + field = nitf_Field_construct(NITF_ICOM_SZ, NITF_BCS_A, error); + if (!field) goto CATCH_ERROR; + memset(commentBuf, 0, NITF_ICOM_SZ + 1); + + length = comment != NULL ? strlen(comment) : 0; + + if (length > 0) + memcpy(commentBuf, comment, length > NITF_ICOM_SZ ? NITF_ICOM_SZ : length); + + /* Warning: if the comment string is greater than the size of the + * field,an error will be set -- which is why we copy it here + * It might be nice to have a size param in nitf_Field_setString */ + if (!nitf_Field_setString(field, commentBuf, error)) + goto CATCH_ERROR; + + /* find the iter where we want to insert */ + iterPos = nitf_List_at(subhdr->imageComments, position); + if (!nitf_List_insert(subhdr->imageComments, iterPos, field, error)) + goto CATCH_ERROR; + + /* always set the numComments back */ + NITF_SNPRINTF(numCommentBuf, NITF_NICOM_SZ + 1, "%.*d", + NITF_NICOM_SZ, ++numComments); + nitf_Field_setRawData(subhdr->numImageComments, + numCommentBuf, NITF_NICOM_SZ, error); + } + else + { + nitf_Error_init(error, + "insertComment -> can't add another comment", + NITF_CTXT, NITF_ERR_INVALID_PARAMETER); + goto CATCH_ERROR; + } + return position; + +CATCH_ERROR: + return -1; +} + +NITFAPI(NITF_BOOL) nitf_ImageSubheader_removeImageComment +( + nitf_ImageSubheader * subhdr, + int position, + nitf_Error * error +) +{ + nitf_Uint32 numComments; /* number of comments */ + char commentBuf[NITF_NICOM_SZ + 1]; + nitf_ListIterator iterPos; + nitf_Field* field = NULL; + + NITF_TRY_GET_UINT32(subhdr->numImageComments, &numComments, error); + numComments = numComments < 0 ? 0 : numComments; + + /* see if we can really remove anything */ + if (numComments > 0 && position >= 0 && position < numComments) + { + + iterPos = nitf_List_at(subhdr->imageComments, position); + field = (nitf_Field*)nitf_ListIterator_get(&iterPos); + if (field) nitf_Field_destruct(&field); + if (!nitf_List_remove(subhdr->imageComments, &iterPos)) + goto CATCH_ERROR; + + /* always set the numComments back */ + NITF_SNPRINTF(commentBuf, NITF_NICOM_SZ + 1, "%.*d", + NITF_NICOM_SZ, --numComments); + nitf_Field_setRawData(subhdr->numImageComments, + commentBuf, NITF_NICOM_SZ, error); + } + else + { + nitf_Error_init(error, + "removeComment -> Invalid index, or nothing to remove", + NITF_CTXT, NITF_ERR_INVALID_PARAMETER); + goto CATCH_ERROR; + } + return NITF_SUCCESS; + +CATCH_ERROR: + return NITF_FAILURE; +} + diff --git a/modules/c/nitf/source/ImageWriter.c b/modules/c/nitf/source/ImageWriter.c new file mode 100644 index 000000000..0627e3a60 --- /dev/null +++ b/modules/c/nitf/source/ImageWriter.c @@ -0,0 +1,320 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/ImageWriter.h" +#include "nitf/ImageIO.h" +#include "nitf/PluginRegistry.h" + +/* + * Private implementation struct + */ +typedef struct _ImageWriterImpl +{ + nitf_Uint32 numBitsPerPixel; + nitf_Uint32 numImageBands; + nitf_Uint32 numMultispectralImageBands; + nitf_Uint32 numRows; + nitf_Uint32 numCols; + nitf_ImageSource *imageSource; + nitf_ImageIO *imageBlocker; + NRT_BOOL directBlockWrite; + +} ImageWriterImpl; + + + +NITFPRIV(void) ImageWriter_destruct(NITF_DATA * data) +{ + ImageWriterImpl *impl = (ImageWriterImpl *) data; + + if (impl) + { + if (impl->imageBlocker) + nitf_ImageIO_destruct(&impl->imageBlocker); + if (impl->imageSource) + nitf_ImageSource_destruct(&impl->imageSource); + NITF_FREE(impl); + } +} + + +NITFPRIV(NITF_BOOL) ImageWriter_write(NITF_DATA * data, + nitf_IOInterface* output, + nitf_Error * error) +{ + nitf_Uint8 **user = NULL; + nitf_Uint8 *userContig = NULL; + nitf_Uint32 row, band, block; + size_t rowSize, blockSize, numBlocks; + nitf_Uint32 numImageBands = 0; + nitf_Off offset; + nitf_BandSource *bandSrc = NULL; + nitf_BlockingInfo* blockInfo = NULL; + nitf_ImageIO* imageIO = NULL; + ImageWriterImpl *impl = (ImageWriterImpl *) data; + NITF_BOOL rc = NITF_SUCCESS; + + numImageBands = impl->numImageBands + impl->numMultispectralImageBands; + rowSize = impl->numCols * NITF_NBPP_TO_BYTES(impl->numBitsPerPixel); + + + offset = nitf_IOInterface_tell(output, error); + if (!NITF_IO_SUCCESS(offset)) + goto CATCH_ERROR; + + if (!nitf_ImageIO_setFileOffset(impl->imageBlocker, offset, error)) + goto CATCH_ERROR; + + if (!nitf_ImageIO_writeSequential(impl->imageBlocker, output, error)) + goto CATCH_ERROR; + + /* Direct block write mode only supported for a single band currently */ + if(impl->directBlockWrite && numImageBands == 1) + { + imageIO = impl->imageBlocker; + + blockInfo = nitf_ImageIO_getBlockingInfo(imageIO, output, error); + if (blockInfo == NULL) + return NITF_FAILURE; + + numBlocks = blockInfo->numBlocksPerRow * blockInfo->numBlocksPerCol; + blockSize = blockInfo->length * NITF_NBPP_TO_BYTES(impl->numBitsPerPixel); + + nitf_BlockingInfo_destruct(&blockInfo); + + userContig = (nitf_Uint8 *) NITF_MALLOC(sizeof(nitf_Uint8*) * blockSize); + if (!userContig) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), NITF_CTXT, + NITF_ERR_MEMORY); + goto CATCH_ERROR; + } + + band = 0; + + /* For each block, read the data and write out as-is without any re-arranging the data + Data should be copied into userContig as the underlying block will be discarded + with each read */ + for(block = 0; block < numBlocks; ++block) + { + bandSrc = nitf_ImageSource_getBand(impl->imageSource, + band, error); + if (bandSrc == NULL) + return NITF_FAILURE; + + /* Assumes this will be reading block number 'block' */ + if (!(*(bandSrc->iface->read)) (bandSrc->data, (char *) userContig, + (size_t) blockSize, error)) + { + goto CATCH_ERROR; + + } + + if(!nitf_ImageIO_writeBlockDirect(imageIO, + output, + userContig, + block, + error)) + goto CATCH_ERROR; + } + } + else + { + user = (nitf_Uint8 **) NITF_MALLOC(sizeof(nitf_Uint8*) * numImageBands); + if (!user) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), NITF_CTXT, + NITF_ERR_MEMORY); + goto CATCH_ERROR; + } + for (band = 0; band < numImageBands; band++) + { + user[band] = (nitf_Uint8 *) NITF_MALLOC(rowSize); + if (!user[band]) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), NITF_CTXT, + NITF_ERR_MEMORY); + goto CATCH_ERROR; + } + } + + for (row = 0; row < impl->numRows; ++row) + { + for (band = 0; band < numImageBands; ++band) + { + bandSrc = nitf_ImageSource_getBand(impl->imageSource, + band, error); + if (bandSrc == NULL) + return NITF_FAILURE; + + if (!(*(bandSrc->iface->read)) (bandSrc->data, (char *) user[band], + (size_t) rowSize, error)) + { + goto CATCH_ERROR; + } + } + + if (!nitf_ImageIO_writeRows(impl->imageBlocker, output, 1, user, error)) + goto CATCH_ERROR; + } + } + + if (!nitf_ImageIO_writeDone(impl->imageBlocker, output, error)) + goto CATCH_ERROR; + + goto CLEANUP; + +CATCH_ERROR: + rc = NITF_FAILURE; + +CLEANUP: + for (band = 0; band < numImageBands; band++) + { + if (user != NULL && user[band] != NULL) + NITF_FREE(user[band]); + } + NITF_FREE(user); + if(userContig != NULL) + NITF_FREE(userContig); + return rc; +} + +NITFAPI(nitf_ImageWriter *) nitf_ImageWriter_construct( + nitf_ImageSubheader *subheader, + nrt_HashTable* options, + nitf_Error * error) +{ + static nitf_IWriteHandler iWriteHandler = + { + &ImageWriter_write, + &ImageWriter_destruct + }; + + ImageWriterImpl *impl = NULL; + nitf_ImageWriter *imageWriter = NULL; + char compBuf[NITF_IC_SZ + 1]; /* holds the compression string */ + nitf_CompressionInterface *compIface = NULL; + + impl = (ImageWriterImpl *) NITF_MALLOC(sizeof(ImageWriterImpl)); + if (!impl) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), NITF_CTXT, + NITF_ERR_MEMORY); + goto CATCH_ERROR; + } + memset(impl, 0, sizeof(ImageWriterImpl)); + + NITF_TRY_GET_UINT32(subheader->numBitsPerPixel, &impl->numBitsPerPixel, error); + NITF_TRY_GET_UINT32(subheader->numImageBands, &impl->numImageBands, error); + NITF_TRY_GET_UINT32(subheader->numMultispectralImageBands, &impl->numMultispectralImageBands, error); + NITF_TRY_GET_UINT32(subheader->numRows, &impl->numRows, error); + NITF_TRY_GET_UINT32(subheader->numCols, &impl->numCols, error); + + impl->imageSource = NULL; + impl->directBlockWrite = 0; + + + /* Check for compression and get compression interface */ + /* get the compression string */ + + nitf_Field_get(subheader->NITF_IC, + compBuf, NITF_CONV_STRING, NITF_IC_SZ + 1, error); + + if(memcmp(compBuf, "NC", 2) != 0 && memcmp(compBuf, "NM", 2) != 0) + { + /* get the compression interface */ + compIface = nitf_PluginRegistry_retrieveCompInterface(compBuf, error); + if (compIface == NULL) + { + goto CATCH_ERROR; + } + } + + impl->imageBlocker = nitf_ImageIO_construct(subheader, 0, 0, + compIface, + NULL, + options, + error); + if (!impl->imageBlocker) + goto CATCH_ERROR; + + imageWriter = (nitf_ImageWriter *) NITF_MALLOC(sizeof(nitf_ImageWriter)); + if (!imageWriter) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), NITF_CTXT, + NITF_ERR_MEMORY); + goto CATCH_ERROR; + } + memset(imageWriter, 0, sizeof(nitf_ImageWriter)); + + imageWriter->data = impl; + imageWriter->iface = &iWriteHandler; + return imageWriter; + + CATCH_ERROR: + if (impl && impl->imageBlocker) + nitf_ImageIO_destruct(&impl->imageBlocker); + if (impl) + NITF_FREE(impl); + return NULL; +} + + +NITFAPI(NITF_BOOL) nitf_ImageWriter_attachSource(nitf_ImageWriter * imageWriter, + nitf_ImageSource *imageSource, nitf_Error * error) +{ + ImageWriterImpl *impl = (ImageWriterImpl*)imageWriter->data; + + if (impl->imageSource != NULL) + { + nitf_Error_init(error, "Image source already attached", + NITF_CTXT, NITF_ERR_INVALID_PARAMETER); + return NITF_FAILURE; + } + + impl->imageSource = imageSource; + return NITF_SUCCESS; +} + + +NITFAPI(int) nitf_ImageWriter_setWriteCaching(nitf_ImageWriter *imageWriter, + int enable) +{ + ImageWriterImpl *impl = (ImageWriterImpl*)imageWriter->data; + return(nitf_ImageIO_setWriteCaching(impl->imageBlocker, enable)); +} + +NITFAPI(void) nitf_ImageWriter_setDirectBlockWrite(nitf_ImageWriter *imageWriter, + int enable) +{ + ImageWriterImpl *impl = (ImageWriterImpl*)imageWriter->data; + impl->directBlockWrite = enable; +} + +NITFAPI(NITF_BOOL) nitf_ImageWriter_setPadPixel(nitf_ImageWriter* imageWriter, + nitf_Uint8* value, + nitf_Uint32 length, + nitf_Error* error) +{ + ImageWriterImpl *impl = (ImageWriterImpl*)imageWriter->data; + return nitf_ImageIO_setPadPixel(impl->imageBlocker, value, length, error); +} diff --git a/modules/c/nitf/source/LabelSegment.c b/modules/c/nitf/source/LabelSegment.c new file mode 100644 index 000000000..f05c44b0c --- /dev/null +++ b/modules/c/nitf/source/LabelSegment.c @@ -0,0 +1,112 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/LabelSegment.h" + +NITFAPI(nitf_LabelSegment *) nitf_LabelSegment_construct(nitf_Error * + error) +{ + nitf_LabelSegment *segment = + (nitf_LabelSegment *) NITF_MALLOC(sizeof(nitf_LabelSegment)); + + if (!segment) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + return NULL; + } + + /* The label offset in the file */ + segment->offset = 0; + /* The label end (offset + length label) */ + segment->end = 0; + + /* This object gets created NOW */ + segment->subheader = NULL; + segment->subheader = nitf_LabelSubheader_construct(error); + if (!segment->subheader) + { + nitf_LabelSegment_destruct(&segment); + return NULL; + } + /* Yes! We have a success */ + return segment; +} + + +NITFAPI(nitf_LabelSegment *) nitf_LabelSegment_clone(nitf_LabelSegment * + source, + nitf_Error * error) +{ + nitf_LabelSegment *segment = NULL; + + if (source) + { + segment = + (nitf_LabelSegment *) NITF_MALLOC(sizeof(nitf_LabelSegment)); + + if (!segment) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + return NULL; + } + /* The label offset in the file */ + segment->offset = source->offset; + /* The label end (offset + length label) */ + segment->end = source->end; + + /* Just in case we self-destruct */ + segment->subheader = NULL; + segment->subheader = + nitf_LabelSubheader_clone(source->subheader, error); + if (!segment->subheader) + { + nitf_LabelSegment_destruct(&segment); + return NULL; + } + } + else + { + nitf_Error_initf(error, + NITF_CTXT, + NITF_ERR_INVALID_OBJECT, + "Trying to clone NULL pointer"); + } + /* Yes! We have a success */ + return segment; +} + + +NITFAPI(void) nitf_LabelSegment_destruct(nitf_LabelSegment ** segment) +{ + if (*segment) + { + if ((*segment)->subheader) + { + /* Destroy subheader info */ + nitf_LabelSubheader_destruct(&(*segment)->subheader); + } + } + NITF_FREE(*segment); + *segment = NULL; +} diff --git a/modules/c/nitf/source/LabelSubheader.c b/modules/c/nitf/source/LabelSubheader.c new file mode 100644 index 000000000..a4db83dfa --- /dev/null +++ b/modules/c/nitf/source/LabelSubheader.c @@ -0,0 +1,185 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/LabelSubheader.h" + +#define _NITF_CONSTRUCT_FIELD(OWNER, ID, TYPE) \ + OWNER->ID = nitf_Field_construct(ID##_SZ, TYPE, error); \ + if (!OWNER->ID) goto CATCH_ERROR; + +#define _NITF_CLONE_FIELD(DEST, SOURCE, ID) \ + DEST->ID = nitf_Field_clone(SOURCE->ID, error); \ + if (!DEST->ID) goto CATCH_ERROR; + +#define _NITF_DESTRUCT_FIELD(OWNER, ID) \ + if (OWNER->ID) nitf_Field_destruct(OWNER->ID); + +NITFAPI(nitf_LabelSubheader *) +nitf_LabelSubheader_construct(nitf_Error * error) +{ + /* Start by allocating the header */ + nitf_LabelSubheader *subhdr = (nitf_LabelSubheader *) + NITF_MALLOC(sizeof(nitf_LabelSubheader)); + + /* Return now if we have a problem above */ + if (!subhdr) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + return NULL; + } + + subhdr->extendedSection = NULL; + subhdr->securityGroup = NULL; + subhdr->securityGroup = nitf_FileSecurity_construct(error); + if (!subhdr->securityGroup) + { + nitf_LabelSubheader_destruct(&subhdr); + goto CATCH_ERROR; + } + _NITF_CONSTRUCT_FIELD(subhdr, NITF_LA, NITF_BCS_A); + _NITF_CONSTRUCT_FIELD(subhdr, NITF_LID, NITF_BCS_A); + _NITF_CONSTRUCT_FIELD(subhdr, NITF_LSCLAS, NITF_BCS_A); + + _NITF_CONSTRUCT_FIELD(subhdr, NITF_ENCRYP, NITF_BCS_A); + _NITF_CONSTRUCT_FIELD(subhdr, NITF_LFS, NITF_BCS_A); + + _NITF_CONSTRUCT_FIELD(subhdr, NITF_LCW, NITF_BCS_N); + _NITF_CONSTRUCT_FIELD(subhdr, NITF_LCH, NITF_BCS_N); + _NITF_CONSTRUCT_FIELD(subhdr, NITF_LDLVL, NITF_BCS_N); + _NITF_CONSTRUCT_FIELD(subhdr, NITF_LALVL, NITF_BCS_N); + _NITF_CONSTRUCT_FIELD(subhdr, NITF_LLOCR, NITF_BCS_N); + _NITF_CONSTRUCT_FIELD(subhdr, NITF_LLOCC, NITF_BCS_N); + + _NITF_CONSTRUCT_FIELD(subhdr, NITF_LTC, NITF_BINARY); + _NITF_CONSTRUCT_FIELD(subhdr, NITF_LBC, NITF_BINARY); + + _NITF_CONSTRUCT_FIELD(subhdr, NITF_LXSHDL, NITF_BCS_N); + _NITF_CONSTRUCT_FIELD(subhdr, NITF_LXSOFL, NITF_BCS_N); + + subhdr->extendedSection = nitf_Extensions_construct(error); + if (!subhdr->extendedSection) + goto CATCH_ERROR; + + return subhdr; + +CATCH_ERROR: + /* destruct if it was allocated */ + nitf_LabelSubheader_destruct(&subhdr); + return NULL; +} + + +NITFAPI(nitf_LabelSubheader *) +nitf_LabelSubheader_clone(nitf_LabelSubheader * source, nitf_Error * error) +{ + nitf_LabelSubheader *subhdr = NULL; + if (source) + { + subhdr = nitf_LabelSubheader_construct(error); + if (!subhdr) + return NULL; + + /* now, destruct the NEW security group, and clone it + * so that everything is in sync */ + nitf_FileSecurity_destruct(&subhdr->securityGroup); + subhdr->securityGroup = + nitf_FileSecurity_clone(source->securityGroup, error); + + /* Copy some fields */ + _NITF_CLONE_FIELD(subhdr, source, NITF_LA); + _NITF_CLONE_FIELD(subhdr, source, NITF_LID); + _NITF_CLONE_FIELD(subhdr, source, NITF_LSCLAS); + + _NITF_CLONE_FIELD(subhdr, source, NITF_ENCRYP); + _NITF_CLONE_FIELD(subhdr, source, NITF_LFS); + + _NITF_CLONE_FIELD(subhdr, source, NITF_LCW); + _NITF_CLONE_FIELD(subhdr, source, NITF_LCH); + _NITF_CLONE_FIELD(subhdr, source, NITF_LDLVL); + _NITF_CLONE_FIELD(subhdr, source, NITF_LALVL); + _NITF_CLONE_FIELD(subhdr, source, NITF_LLOCR); + _NITF_CLONE_FIELD(subhdr, source, NITF_LLOCC); + + _NITF_CLONE_FIELD(subhdr, source, NITF_LTC); + _NITF_CLONE_FIELD(subhdr, source, NITF_LBC); + + _NITF_CLONE_FIELD(subhdr, source, NITF_LXSHDL); + _NITF_CLONE_FIELD(subhdr, source, NITF_LXSOFL); + + /* init to NULL in case */ + subhdr->extendedSection = NULL; + + if (source->extendedSection) + { + subhdr->extendedSection = + nitf_Extensions_clone(source->extendedSection, error); + + if (!subhdr->extendedSection) + goto CATCH_ERROR; + } + + return subhdr; + } + +CATCH_ERROR: + nitf_LabelSubheader_destruct(&subhdr); + return NULL; +} + + +NITFAPI(void) nitf_LabelSubheader_destruct(nitf_LabelSubheader ** subhdr) +{ + if (!*subhdr) + return; + + if ((*subhdr)->extendedSection) + { + nitf_Extensions_destruct(&(*subhdr)->extendedSection); + } + if ((*subhdr)->securityGroup) + { + nitf_FileSecurity_destruct(&(*subhdr)->securityGroup); + NITF_FREE((*subhdr)->securityGroup); + (*subhdr)->securityGroup = NULL; + } + + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_LA); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_LID); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_LSCLAS); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_ENCRYP); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_LFS); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_LCW); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_LCH); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_LDLVL); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_LALVL); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_LLOCR); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_LLOCC); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_LTC); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_LBC); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_LXSHDL); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_LXSOFL); + + NITF_FREE(*subhdr); + *subhdr = NULL; +} + diff --git a/modules/c/nitf/source/LookupTable.c b/modules/c/nitf/source/LookupTable.c new file mode 100644 index 000000000..5a1ec7cd9 --- /dev/null +++ b/modules/c/nitf/source/LookupTable.c @@ -0,0 +1,149 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/LookupTable.h" + +NITFAPI(nitf_LookupTable *) nitf_LookupTable_construct(nitf_Uint32 tables, + nitf_Uint32 entries, + nitf_Error * error) +{ + nitf_LookupTable *lt = NULL; + + lt = (nitf_LookupTable *) NITF_MALLOC(sizeof(nitf_LookupTable)); + + if (!lt) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + return NULL; + } + + lt->tables = tables; + lt->entries = entries; + lt->table = NULL; + if (!nitf_LookupTable_init(lt, tables, entries, NULL, error)) + { + nitf_LookupTable_destruct(<); + lt = NULL; + } + + return lt; +} + + +NITFAPI(nitf_LookupTable *) nitf_LookupTable_clone(nitf_LookupTable * + donor, + nitf_Error * error) +{ + nitf_LookupTable *lt; + + if (!donor) + { + nitf_Error_initf(error, + NITF_CTXT, + NITF_ERR_INVALID_OBJECT, + "Trying to clone NULL pointer"); + return NULL; + } + if (!(donor->tables * donor->entries)) + { + nitf_Error_initf(error, + NITF_CTXT, + NITF_ERR_INVALID_OBJECT, + "Trying to clone bad LUT (size)"); + return NULL; + } + if (!donor->table) + { + nitf_Error_initf(error, + NITF_CTXT, + NITF_ERR_INVALID_OBJECT, + "Trying to clone bad LUT (pointer)"); + return NULL; + } + lt = nitf_LookupTable_construct(donor->tables, donor->entries, error); + if (lt) + { + memcpy(lt->table, donor->table, (donor->tables * donor->entries)); + } + return lt; +} + + +NITFAPI(void) nitf_LookupTable_destruct(nitf_LookupTable ** lt) +{ + if (*lt) + { + if ((*lt)->table) + { + NITF_FREE((*lt)->table); + } + NITF_FREE((*lt)); + *lt = NULL; + } +} + + +NITFAPI(NITF_BOOL) nitf_LookupTable_init(nitf_LookupTable * lut, + nitf_Uint32 numTables, + nitf_Uint32 numEntries, + const NITF_DATA * tables, + nitf_Error * error) +{ + + /* Look for existing table of a different size */ + if (lut->tables != numTables || lut->entries != numEntries) + { + NITF_FREE(lut->table); + lut->table = NULL; + } + + lut->tables = numTables; + lut->entries = numEntries; + + /* only create the table data if we really should */ + if (numTables > 0 && numEntries > 0) + { + if (!lut->table) + { + lut->table = (nitf_Uint8 *) NITF_MALLOC(numTables * numEntries); + if (!lut->table) + { + nitf_Error_initf(error, NITF_CTXT, + NITF_ERR_MEMORY, + "Error allocating look-up table"); + return NITF_FAILURE; + } + } + + /* only copy if one existed */ + if (tables) + { + memcpy(lut->table, tables, numTables * numEntries); + } + } + else + { + lut->table = NULL; + } + return NITF_SUCCESS; +} diff --git a/modules/c/nitf/source/PluginRegistry.c b/modules/c/nitf/source/PluginRegistry.c new file mode 100644 index 000000000..4beab48ad --- /dev/null +++ b/modules/c/nitf/source/PluginRegistry.c @@ -0,0 +1,872 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; + * If not, see . + * + */ + +#include "nitf/PluginRegistry.h" + +NITFPRIV(nitf_PluginRegistry *) implicitConstruct(nitf_Error * error); +NITFPRIV(void) implicitDestruct(nitf_PluginRegistry ** reg); +NITFPRIV(void) exitListener(void); +NITFPRIV(NITF_BOOL) insertCreator(nitf_DLL* dso, + nitf_HashTable* handlers, + const char* ident, + const char* suffix, + nitf_Error* error); + +#ifndef WIN32 + static nitf_Mutex __PluginRegistryLock = NITF_MUTEX_INIT; + static const char DIR_DELIMITER = '/'; +#else + static nitf_Mutex __PluginRegistryLock = NULL; + static long __PluginRegistryInitLock = 0; + static const char DIR_DELIMITER = '\\'; +#endif +/* + * This function retrieves the mutex that is necessary + * to establish the singleton in a portable way. + * + */ + +#ifdef WIN32 +NITFPRIV(nitf_Mutex*) GET_MUTEX() +{ + if (__PluginRegistryLock == NULL) + { + while (InterlockedExchange(&__PluginRegistryInitLock, 1) == 1) + /* loop, another thread own the lock */ ; + if (__PluginRegistryLock == NULL) + nitf_Mutex_init(&__PluginRegistryLock); + InterlockedExchange(&__PluginRegistryInitLock, 0); + } + return &__PluginRegistryLock; +} + +static +NITF_BOOL isDelimiter(char ch) +{ + /* On Windows, allow either delimiter */ + return (ch == '/' || ch == '\\'); +} +#else +#define GET_MUTEX() &__PluginRegistryLock + +static +NITF_BOOL isDelimiter(char ch) +{ + /* On Unix, allow only forward slash */ + return (ch == '/'); +} +#endif + +/* + * Retrieves the singleton instance. If there is none + * already, one is created. + * + * When we create a new registry, we call the load function + * in an attempt to load up all DSO references + * + */ +NITFPROT(nitf_PluginRegistry *) + nitf_PluginRegistry_getInstance(nitf_Error * error) +{ + static nitf_PluginRegistry *theInstance = NULL; + + /*nitf_Mutex mutex = GET_MUTEX();*/ + /*nitf_Mutex_lock(&mutex);*/ + + if (theInstance == NULL) + { + nitf_Mutex_lock( GET_MUTEX()); + + /* If this call below fails, the error will have been */ + /* constructed */ + if (theInstance == NULL) + { + theInstance = implicitConstruct(error); + /* If this succeeded... */ + if (theInstance) + { + const NITF_BOOL loadedOK = + nitf_PluginRegistry_load(theInstance, error); + if (loadedOK) + { + atexit(exitListener); + } + else + { + /* Sorry, no go... */ + implicitDestruct(&theInstance); + } + } + } + + nitf_Mutex_unlock( GET_MUTEX()); + } + + + return theInstance; +} + +NITFPRIV(NITF_BOOL) insertPlugin(nitf_PluginRegistry * reg, + char **ident, + nitf_DLL * dll, + nitf_Error * error) +{ + nitf_HashTable *hash = NULL; + int i; + int ok; + const char* suffix = NULL; + + /* Load the DLL */ + if (!nitf_List_pushBack(reg->dsos, dll, error)) + { + return NITF_FAILURE; + } + + + if (strcmp(ident[0], NITF_PLUGIN_TRE_KEY) == 0) + { + hash = reg->treHandlers; + suffix = NITF_PLUGIN_HOOK_SUFFIX; + } + else if (strcmp(ident[0], NITF_PLUGIN_COMPRESSION_KEY) == 0) + { + hash = reg->compressionHandlers; + suffix = NITF_PLUGIN_CONSTRUCT_SUFFIX; + } + else if (strcmp(ident[0], NITF_PLUGIN_DECOMPRESSION_KEY) == 0) + { + hash = reg->decompressionHandlers; + suffix = NITF_PLUGIN_CONSTRUCT_SUFFIX; + } + else + { + nitf_Error_initf(error, + NITF_CTXT, + NITF_ERR_INVALID_OBJECT, + "The identity [%s] is not supported", ident[0]); + return NITF_FAILURE; + } + /* Go through each identity and add it as a creator */ + for (i = 1;; i++) + { + const char *key = ident[i]; + + if (key == NULL) + break; + + /* no more */ + ok = insertCreator(dll, hash, key, suffix, error); + if (!ok) + { + return NITF_FAILURE; + } + + } + return NITF_SUCCESS; +} + + +NITFPRIV(nitf_PluginRegistry *) implicitConstruct(nitf_Error * error) +{ + size_t pathLen; + const char *pluginEnvVar; + + /* Create the registry object */ + nitf_PluginRegistry *reg = + (nitf_PluginRegistry *) NITF_MALLOC(sizeof(nitf_PluginRegistry)); + + /* If we have a memory problem, init our error struct and return */ + if (!reg) + { + nitf_Error_init(error, + NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + return NULL; + } + + /* set these to NULL to possibly protect us later */ + reg->compressionHandlers = NULL; + reg->treHandlers = NULL; + reg->decompressionHandlers = NULL; + reg->dsos = NULL; + + reg->dsos = nitf_List_construct(error); + if (!reg->dsos) + { + implicitDestruct(®); + return NULL; + } + + + /* Construct our hash object */ + reg->treHandlers = nitf_HashTable_construct(NITF_TRE_HASH_SIZE, error); + + /* If we have a problem, get rid of this object and return */ + if (!reg->treHandlers) + { + implicitDestruct(®); + return NULL; + } + + /* do not adopt the data - we will clean it up ourselves */ + nitf_HashTable_setPolicy(reg->treHandlers, NITF_DATA_RETAIN_OWNER); + + reg->compressionHandlers = + nitf_HashTable_construct(NITF_COMPRESSION_HASH_SIZE, error); + + + /* If we have a problem, get rid of this object and return */ + if (!reg->compressionHandlers) + { + implicitDestruct(®); + return NULL; + } + + /* do not adopt the data - we will clean it up ourselves */ + nitf_HashTable_setPolicy(reg->compressionHandlers, NITF_DATA_RETAIN_OWNER); + + reg->decompressionHandlers = + nitf_HashTable_construct(NITF_DECOMPRESSION_HASH_SIZE, error); + + /* If we have a problem, get rid of this object and return */ + if (!reg->decompressionHandlers) + { + implicitDestruct(®); + return NULL; + } + + /* do not adopt the data - we will clean it up ourselves */ + nitf_HashTable_setPolicy(reg->decompressionHandlers, + NITF_DATA_RETAIN_OWNER); + + /* Start with a clean slate */ + memset(reg->path, 0, NITF_MAX_PATH); + + /* Take the environment variable, or... */ + pluginEnvVar = getenv(NITF_PLUGIN_PATH); + if (!pluginEnvVar) + { + /* Take the default path */ + /*strcpy(reg->path, NITF_DEFAULT_PLUGIN_PATH);*/ + return reg; + } + else + { + strcpy(reg->path, pluginEnvVar); + } + /* + * If the we have a user-defined path, they might not + * have terminated their environment variable with a + * trailing delimiter. No problem, we can do it for them. + */ + pathLen = strlen(reg->path); + if (pathLen > 0 && !isDelimiter(reg->path[pathLen - 1])) + { + /* Need to append delimiter to end */ + reg->path[pathLen++] = DIR_DELIMITER; + reg->path[pathLen++] = '\0'; + } + + /* Return the object, its okay! */ + return reg; +} + +/* + * This function is a garbage-collector. + * It is called at exit time. In the event that the singleton + * is properly returned, it destructs it. + * + * Since this function is only registered in the getInstance() + * call in the first place, it is presumed to exist already, and + * thereby need destruction. + * + */ +NITFPRIV(void) exitListener(void) +{ + nitf_Error error; + nitf_Mutex* mutex = GET_MUTEX(); + nitf_PluginRegistry *single = nitf_PluginRegistry_getInstance(&error); + if (single) + { + int unloadRet = nitf_PluginRegistry_unload(single, &error); + if (unloadRet) + { + implicitDestruct(&single); + } + } + nitf_Mutex_delete(mutex); +} + +NITFPRIV(void) implicitDestruct(nitf_PluginRegistry ** reg) +{ + + /* If it is not NULL set */ + if (*reg) + { + if ((*reg)->dsos) + nitf_List_destruct(&(*reg)->dsos); + + if ((*reg)->treHandlers) + nitf_HashTable_destruct(&(*reg)->treHandlers); + if ((*reg)->compressionHandlers) + nitf_HashTable_destruct(&(*reg)->compressionHandlers); + if ((*reg)->decompressionHandlers) + nitf_HashTable_destruct(&(*reg)->decompressionHandlers); + NITF_FREE(*reg); + *reg = NULL; + } +} + +/* + * Initialize a DSO. The init hook is retrieved and called once + * when the DSO is loaded + */ + +NITFPRIV(char **) doInit(nitf_DLL * dll, + const char *prefix, nitf_Error * error) +{ + NITF_PLUGIN_INIT_FUNCTION init; + char **ident; + + char name[NITF_MAX_PATH]; + memset(name, 0, NITF_MAX_PATH); + NITF_SNPRINTF(name, NITF_MAX_PATH, "%s%s", prefix, NITF_PLUGIN_INIT_SUFFIX); + init = (NITF_PLUGIN_INIT_FUNCTION) nitf_DLL_retrieve(dll, name, error); + if (!init) + { + nitf_Error_print(error, stdout, "Invalid init hook in DSO"); + return NULL; + } + + /* Else, call it */ + + ident = (*init)(error); + if (!ident) + { + nitf_Error_initf(error, + NITF_CTXT, + NITF_ERR_INVALID_OBJECT, + "The plugin [%s] is not retrievable", prefix); + return NULL; + } + return ident; +} + + +/* + * Cleanup the DLL. This is called once when the registry is + * shut down. + */ +NITFPRIV(int) doCleanup(nitf_DLL * dll, nitf_Error* error) +{ + NITF_PLUGIN_CLEANUP_FUNCTION cleanup; + const char* cleanupName = NITF_PLUGIN_CLEANUP; + + cleanup = (NITF_PLUGIN_CLEANUP_FUNCTION)nitf_DLL_retrieve(dll, + cleanupName, + error); + if (!cleanup) + { + return 0; + } + /* Else, call it */ + cleanup(); + + return 1; +} + + +/*! + * Unload the plugin registry. This will unload the DLLs and free + * the nodes in the data structure containing them. + * + * \param reg The registry + * \param error An error to populate on failure + * \return 1 on success, 0 on failure + * + */ +NITFPRIV(NITF_BOOL) unloadDSO(nitf_DLL* dll, nitf_Error * error) +{ + + NITF_BOOL ok = NITF_SUCCESS; + + + if (nitf_DLL_isValid(dll)) + { + doCleanup(dll, error); + + /* destroy the lib */ + ok &= nitf_DLL_unload(dll, error); + if ( dll->libname ) + { + +#if NITF_DEBUG_PLUGIN_REG + printf("Unloaded dll with name [%s]\n", dll->libname); +#endif + + NITF_FREE( dll->libname ); + dll->libname = NULL; + } + + nitf_DLL_destruct(&dll); + + + } + return ok; +} + + + + +NITFPROT(NITF_BOOL) nitf_PluginRegistry_unload(nitf_PluginRegistry * reg, + nitf_Error * error) +{ + + /* Pop the front off, until the list is empty */ + nitf_List* l = reg->dsos; + NITF_BOOL success = NITF_SUCCESS; + while ( ! nitf_List_isEmpty(l) ) + { + nitf_DLL* dso = (nitf_DLL*)nitf_List_popFront(l); + success &= unloadDSO(dso, error); + } + return success; + +} + + +NITFAPI(NITF_BOOL) + nitf_PluginRegistry_loadPlugin(const char* fullName, nitf_Error * error) +{ + + /* For now, the key is the dll name minus the extension */ + char keyName[NITF_MAX_PATH] = ""; + char* p; + int ok; + int i, begin, end; + nitf_DLL *dll; + char **ident; + nitf_PluginRegistry* reg = nitf_PluginRegistry_getInstance(error); + + /* Construct the DLL object */ + dll = nitf_DLL_construct(error); + if (!dll) + { + return NITF_FAILURE; + } + /* Otherwise we can load the DLL */ + if (!nitf_DLL_load(dll, fullName, error)) + { + /* + * If the load failed, we have a set error + * So all we have to do is close shop, go home + */ + return NITF_FAILURE; + } + nitf_Utils_baseName(keyName, fullName, NITF_DLL_EXTENSION); + + /* Now init the plugin!!! */ + ident = doInit(dll, keyName, error); + + /* If no ident, we have a set error and an invalid plugin */ + if (ident) + { + /* I expect to have problems with this now and then */ + ok = insertPlugin(reg, ident, dll, error); + + /* If insertion failed, take our toys and leave */ + if (!ok) + { + return NITF_FAILURE; + } +#if NITF_DEBUG_PLUGIN_REG + printf("Successfully loaded plugin: [%s] at [%p]\n", + keyName, dll); +#endif + return NITF_SUCCESS; + } + return NITF_FAILURE; + +} + + + +NITFAPI(NITF_BOOL) +nitf_PluginRegistry_registerTREHandler(NITF_PLUGIN_INIT_FUNCTION init, + NITF_PLUGIN_TRE_HANDLER_FUNCTION handle, + nitf_Error * error) +{ + + nitf_PluginRegistry* reg = nitf_PluginRegistry_getInstance(error); + + char** ident; + int i = 1; + int ok = 1; + if (!reg) + { + return NITF_FAILURE; + } + if ( (ident = (*init)(error)) == NULL) + { + return NITF_FAILURE; + } + + if (!ident[0] || (strcmp(ident[0], NITF_PLUGIN_TRE_KEY) != 0)) + { + nitf_Error_initf(error, + NITF_CTXT, + NITF_ERR_INVALID_OBJECT, + "Expected a TRE identity"); + return NITF_FAILURE; + } + + for (; ident[i] != NULL; ++i) + { +#if NITF_DEBUG_PLUGIN_REG + if (nitf_HashTable_exists(reg->treHandlers, ident[i])) + { + printf("Warning, static handler overriding [%s] hook", ident); + } +#endif + ok &= nitf_HashTable_insert(reg->treHandlers, ident[i], (NITF_DATA*)handle, error); + } + + return ok; + +} + + +NITFPROT(NITF_BOOL) + nitf_PluginRegistry_internalLoadDir(nitf_PluginRegistry * reg, + const char *dirName, + nitf_Error * error) +{ + const char *name; + size_t sizePath; + nitf_Directory *dir = NULL; + + if (!dirName) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_OPENING_FILE, + "Null directory name"); + return NITF_FAILURE; + } + + dir = nitf_Directory_construct(error); + if (!dir) + { + return NITF_FAILURE; + } + + sizePath = strlen(dirName); + + if (nitf_Directory_exists(dirName)) + { + name = nitf_Directory_findFirstFile(dir, dirName); + if (name) + { + do + { + + char *end; + char fullName[NITF_MAX_PATH]; + int pathSize = sizePath; + memset(fullName, 0, NITF_MAX_PATH); + memcpy(fullName, dirName, sizePath); + if (!isDelimiter(dirName[pathSize - 1])) + fullName[pathSize++] = DIR_DELIMITER; + memcpy(fullName + pathSize, name, strlen(name)); + + /* See if we have .so or .dll extensions */ + if ((end = + (char *) strstr(name, NITF_DLL_EXTENSION)) != NULL) + { + if (!nitf_PluginRegistry_loadPlugin(fullName, error)) + { +#if NITF_DEBUG_PLUGIN_REG + printf("Warning: plugin [%s] failed to load!\n", name); +#endif + } + } + + else + { +#if NITF_DEBUG_PLUGIN_REG + printf("Skipping directory [%s]\n", name); +#endif + } + + name = nitf_Directory_findNextFile(dir); + } + while (name); + } + else + { + printf("Error: %s\n", NITF_STRERROR(NITF_ERRNO)); + } + } + else + { +#if NITF_DEBUG_PLUGIN_REG + fprintf(stdout, + "Could not open plug-in directory '%s'. " + "You may have forgotten to set your NITF_PLUGIN_PATH environment " + "variable : continuing without plugins...\n", dirName); +#endif + } + nitf_Directory_destruct(&dir); + return NITF_SUCCESS; +} + + +NITFPROT(NITF_BOOL) nitf_PluginRegistry_load(nitf_PluginRegistry * reg, + nitf_Error * error) +{ + return nitf_PluginRegistry_internalLoadDir(reg, reg->path, error); +} + + +NITFAPI(NITF_BOOL) nitf_PluginRegistry_loadDir(const char *dirName, + nitf_Error * error) +{ + NITF_BOOL status; + nitf_Mutex mutex; + + /* first, get the registry */ + nitf_PluginRegistry *reg = nitf_PluginRegistry_getInstance(error); + + /* must be thread safe */ + nitf_Mutex_lock( GET_MUTEX() ); + + status = nitf_PluginRegistry_internalLoadDir(reg, dirName, error); + + /* unlock */ + nitf_Mutex_unlock( GET_MUTEX() ); + return status; +} + + + +NITFPROT(NITF_PLUGIN_DECOMPRESSION_CONSTRUCT_FUNCTION) +nitf_PluginRegistry_retrieveDecompConstructor(nitf_PluginRegistry * reg, + const char *ident, + int *hadError, + nitf_Error * error) +{ + + /* We get back a pair from the hash table */ + nitf_Pair *pair; + + /* No error has occurred (yet) */ + *hadError = 0; + + if (!nitf_HashTable_exists(reg->decompressionHandlers, ident)) + { + *hadError = 1; + nitf_Error_init(error, "Decompression handlers not set", NRT_CTXT, + NRT_ERR_DECOMPRESSION); + return NULL; + } + pair = nitf_HashTable_find(reg->decompressionHandlers, ident); + + /* If nothing is there, we don't have a handler, plain and simple */ + if (!pair) + { + nitf_Error_initf(error, NRT_CTXT, NRT_ERR_DECOMPRESSION, + "Don't have a handler for '%s'", + ident); + return NULL; + } + + return (NITF_PLUGIN_DECOMPRESSION_CONSTRUCT_FUNCTION) pair->data; +} + +NITFPROT(NITF_PLUGIN_COMPRESSION_CONSTRUCT_FUNCTION) +nitf_PluginRegistry_retrieveCompConstructor(nitf_PluginRegistry * reg, + const char *ident, + int *hadError, + nitf_Error * error) +{ + + /* We get back a pair from the hash table */ + nitf_Pair *pair; + + /* No error has occurred (yet) */ + *hadError = 0; + + if (!nitf_HashTable_exists(reg->compressionHandlers, ident)) + { + *hadError = 1; + nitf_Error_init(error, "Compression handlers not set", NRT_CTXT, + NRT_ERR_COMPRESSION); + return NULL; + } + pair = nitf_HashTable_find(reg->compressionHandlers, ident); + + /* If nothing is there, we don't have a handler, plain and simple */ + if (!pair) + { + nitf_Error_initf(error, NRT_CTXT, NRT_ERR_COMPRESSION, + "Don't have a handler for '%s'", + ident); + return NULL; + } + + return (NITF_PLUGIN_COMPRESSION_CONSTRUCT_FUNCTION) pair->data; +} + + +NITFPRIV(NITF_BOOL) insertCreator(nitf_DLL* dso, + nitf_HashTable* hash, + const char* ident, + const char* suffix, + nitf_Error* error) +{ + /* We are trying to find tre_main */ + NITF_DLL_FUNCTION_PTR dsoMain = NULL; + + /* Get the name of the handler */ + char name[NITF_MAX_PATH]; + char* p = NULL; + + if (!nitf_DLL_isValid(dso)) + { + nitf_Error_initf(error, + NITF_CTXT, + NITF_ERR_INVALID_PARAMETER, + "DSO is not valid for [%s]", + ident); + + } + + memset(name, 0, NITF_MAX_PATH); + NITF_SNPRINTF(name, NITF_MAX_PATH, "%s%s", ident, suffix); + + nitf_Utils_replace(name, ' ', '_'); + + /* No error has occurred (yet) */ +#if NITF_DEBUG_PLUGIN_REG + printf("Loading function [%s] in dso at [%p]\n", name, dso); +#endif + + /* Retrieve the main */ + dsoMain = nitf_DLL_retrieve(dso, name, error); + + if (!dsoMain) + { + /* If it didnt work, we are done */ + return NITF_FAILURE; + } + +#if NITF_DEBUG_PLUGIN_REG + if (nitf_HashTable_exists(hash, ident)) + { + printf("Warning, overriding [%s] hook", ident); + + } +#endif + + return nitf_HashTable_insert(hash, ident, dsoMain, error); + +} + +/* + * Function is now greatly simplified. We only retrieve TREs from + * the hash table. If they are there, we are good, if not fail + * + * No more talking to the DSOs directly + */ +NITFPROT(nitf_TREHandler*) +nitf_PluginRegistry_retrieveTREHandler(nitf_PluginRegistry * reg, + const char *treIdent, + int *hadError, + nitf_Error * error) +{ + nitf_TREHandler* theHandler; + /* We get back a pair from the hash table */ + nitf_Pair *pair; + /* We are trying to find tre_main */ + NITF_PLUGIN_TRE_HANDLER_FUNCTION treMain = NULL; + + /* No error has occurred (yet) */ + *hadError = 0; + + if (!nitf_HashTable_exists(reg->treHandlers, treIdent)) + { + return NULL; + } + /* Lookup the pair from the hash table, by the tre_id */ + pair = nitf_HashTable_find(reg->treHandlers, treIdent); + + /* If nothing is there, we dont have a handler, plain and simple */ + if (!pair) + return NULL; + + /* If something is, get its DLL part */ + treMain = (NITF_PLUGIN_TRE_HANDLER_FUNCTION) pair->data; + + theHandler = (*treMain)(error); + if (!theHandler) + { + *hadError = 1; + } + return theHandler; +} + +NITFPROT(nitf_CompressionInterface* ) +nitf_PluginRegistry_retrieveCompInterface(const char *comp, + nitf_Error* error) +{ + /* In all cases below, the function we're calling should populate the + * error if one occurs. */ + nitf_PluginRegistry *reg; + nitf_CompressionInterface *compIface; + NITF_PLUGIN_COMPRESSION_CONSTRUCT_FUNCTION constructCompIface; + int hadError = 0; + + /* Find the compression interface here */ + reg = nitf_PluginRegistry_getInstance(error); + if (!reg) + { + return NULL; + } + + /* Now retrieve the comp iface creator */ + constructCompIface = + nitf_PluginRegistry_retrieveCompConstructor(reg, + comp, &hadError, error); + if (hadError || constructCompIface == NULL) + { + return NULL; + } + + /* Now actually construct it */ + compIface = + (nitf_CompressionInterface *) (*constructCompIface) (comp, + error); + if (compIface == NULL) + { + return NULL; + } + + return compIface; +} diff --git a/modules/c/nitf/source/RESegment.c b/modules/c/nitf/source/RESegment.c new file mode 100644 index 000000000..d954061c6 --- /dev/null +++ b/modules/c/nitf/source/RESegment.c @@ -0,0 +1,132 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/RESegment.h" + +NITFAPI(nitf_RESegment *) nitf_RESegment_construct(nitf_Error * error) +{ + nitf_RESegment *segment = + (nitf_RESegment *) NITF_MALLOC(sizeof(nitf_RESegment)); + + if (!segment) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + return NULL; + } + + /* The offset in the file */ + segment->offset = 0; + /* The end (offset + length) */ + segment->end = 0; + + /* This object gets created NOW */ + segment->subheader = NULL; + segment->subheader = nitf_RESubheader_construct(error); + if (!segment->subheader) + { + nitf_RESegment_destruct(&segment); + return NULL; + } + segment->data = NULL; + + /* Yes! We have a success */ + return segment; +} + + +NITFAPI(nitf_RESegment *) nitf_RESegment_clone(nitf_RESegment * source, + nitf_Error * error) +{ + nitf_RESegment *segment = NULL; + + if (source) + { + segment = (nitf_RESegment *) NITF_MALLOC(sizeof(nitf_RESegment)); + + if (!segment) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + return NULL; + } + /* The offset in the file */ + segment->offset = source->offset; + /* The end (offset + length) */ + segment->end = source->end; + + /* Just in case we self-destruct */ + segment->subheader = NULL; + segment->subheader = + nitf_RESubheader_clone(source->subheader, error); + if (!segment->subheader) + { + nitf_RESegment_destruct(&segment); + return NULL; + } + /* Just in case we self-destruct */ + segment->data = NULL; + if (source->data) + { + segment->data = + (char *) NITF_MALLOC(segment->subheader->dataLength); + if (!segment->data) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + nitf_RESegment_destruct(&segment); + return NULL; + } + memcpy(segment->data, source->data, + segment->subheader->dataLength); + } + } + else + { + nitf_Error_initf(error, + NITF_CTXT, + NITF_ERR_INVALID_OBJECT, + "Trying to clone NULL pointer"); + } + /* Yes! We have a success */ + return segment; +} + + +NITFAPI(void) nitf_RESegment_destruct(nitf_RESegment ** segment) +{ + if (*segment) + { + if ((*segment)->subheader) + { + /* Destroy subheader info */ + nitf_RESubheader_destruct(&(*segment)->subheader); + } + if ((*segment)->data) + { + NITF_FREE((*segment)->data); + (*segment)->data = NULL; + } + } + NITF_FREE(*segment); + *segment = NULL; +} diff --git a/modules/c/nitf/source/RESubheader.c b/modules/c/nitf/source/RESubheader.c new file mode 100644 index 000000000..60ab91e45 --- /dev/null +++ b/modules/c/nitf/source/RESubheader.c @@ -0,0 +1,156 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/RESubheader.h" + +#define _NITF_CONSTRUCT_FIELD(OWNER, ID, TYPE) \ + OWNER->ID = nitf_Field_construct(ID##_SZ, TYPE, error); \ + if (!OWNER->ID) goto CATCH_ERROR; + +#define _NITF_CLONE_FIELD(DEST, SOURCE, ID) \ + DEST->ID = nitf_Field_clone(SOURCE->ID, error); \ + if (!DEST->ID) goto CATCH_ERROR; + +#define _NITF_DESTRUCT_FIELD(OWNER, ID) \ + if (OWNER->ID) nitf_Field_destruct(OWNER->ID); + +NITFAPI(nitf_RESubheader *) nitf_RESubheader_construct(nitf_Error * error) +{ + /* Start by allocating the header */ + nitf_RESubheader *subhdr = (nitf_RESubheader *) + NITF_MALLOC(sizeof(nitf_RESubheader)); + + /* Return now if we have a problem above */ + if (!subhdr) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + goto CATCH_ERROR; + } + + subhdr->securityGroup = nitf_FileSecurity_construct(error); + if (!subhdr->securityGroup) + { + nitf_RESubheader_destruct(&subhdr); + goto CATCH_ERROR; + } + + _NITF_CONSTRUCT_FIELD(subhdr, NITF_RE, NITF_BCS_A); + _NITF_CONSTRUCT_FIELD(subhdr, NITF_RESTAG, NITF_BCS_A); + _NITF_CONSTRUCT_FIELD(subhdr, NITF_RESVER, NITF_BCS_N); + _NITF_CONSTRUCT_FIELD(subhdr, NITF_RESCLAS, NITF_BCS_A); + + _NITF_CONSTRUCT_FIELD(subhdr, NITF_RESSHL, NITF_BCS_N); + subhdr->subheaderFields = NULL; + subhdr->dataLength = 0; + + return subhdr; + +CATCH_ERROR: + /* destruct if it was allocated */ + if (subhdr) + nitf_RESubheader_destruct(&subhdr); + return NULL; +} + + +NITFAPI(nitf_RESubheader *) +nitf_RESubheader_clone(nitf_RESubheader * source, nitf_Error * error) +{ + nitf_Uint32 subLen; + nitf_RESubheader *subhdr = NULL; + if (source) + { + subhdr = + (nitf_RESubheader *) NITF_MALLOC(sizeof(nitf_RESubheader)); + if (!subhdr) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + return NULL; + } + + subhdr->securityGroup = + nitf_FileSecurity_clone(source->securityGroup, error); + + if (!subhdr->securityGroup) + goto CATCH_ERROR; + + /* Copy some fields */ + _NITF_CLONE_FIELD(subhdr, source, NITF_RE); + _NITF_CLONE_FIELD(subhdr, source, NITF_RESTAG); + _NITF_CLONE_FIELD(subhdr, source, NITF_RESVER); + _NITF_CLONE_FIELD(subhdr, source, NITF_RESCLAS); + + /* And some ints */ + _NITF_CLONE_FIELD(subhdr, source, NITF_RESSHL); + subhdr->dataLength = source->dataLength; + subhdr->subheaderFields = NULL; + + NITF_TRY_GET_UINT32(source->subheaderFieldsLength, &subLen, error); + if (source->subheaderFields) + { + subhdr->subheaderFields = (char* )NITF_MALLOC(subLen); + if (!subhdr->subheaderFields) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + return NULL; + } + memcpy(subhdr->subheaderFields, + source->subheaderFields, subLen); + } + return subhdr; + } + +CATCH_ERROR: + return NULL; +} + + +NITFAPI(void) nitf_RESubheader_destruct(nitf_RESubheader ** subhdr) +{ + if (!*subhdr) + return; + + if ((*subhdr)->securityGroup) + { + nitf_FileSecurity_destruct(&(*subhdr)->securityGroup); + NITF_FREE((*subhdr)->securityGroup); + (*subhdr)->securityGroup = NULL; + } + if ((*subhdr)->subheaderFields) + { + NITF_FREE((*subhdr)->subheaderFields); + (*subhdr)->subheaderFields = NULL; + } + + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_RE); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_RESTAG); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_RESVER); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_RESCLAS); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_RESSHL); + + NITF_FREE(*subhdr); + *subhdr = NULL; +} + diff --git a/modules/c/nitf/source/Reader.c b/modules/c/nitf/source/Reader.c new file mode 100644 index 000000000..24febc478 --- /dev/null +++ b/modules/c/nitf/source/Reader.c @@ -0,0 +1,1961 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, + * see . + * + */ + +#include "nitf/Reader.h" + +/**************************** + *** NOTE ABOUT THE MACROS *** + ***************************** +All of these macros make the assumption that a label +called CATCH_ERROR exists. This allows macros to +simulate throwing as seen in C++ + +NITF_TRY_GET_UINT32|64() -- these are public macros found in nitf/Value.h +*/ + +/* This macro basically allows exceptions. It performs */ +/* error checking for the user, and thus simplifies the */ +/* code. It should be used any time you want to read a */ +/* field, but be careful with it. You must note the */ +/* assumptions. */ +/* ASSUMPTIONS: */ +/* 1) A nitf_Reader object named reader exists */ +/* 2) CATCH_ERROR exists (see above) */ + +#define TRY_READ_FIELD(own_, fld_) \ + if (!readField(reader, own_->fld_, fld_##_SZ, error)) \ + goto CATCH_ERROR; + +/* This macro makes it easier to read the user-defined */ +/* header data section. The readExtras() method supplies */ +/* the underlying driving call, but it can be generalized */ +/* for this case, and for the extended header components */ +#define TRY_READ_UDHD(reader_) \ + if (!readExtras(reader_, \ + reader->record->header->userDefinedSection, \ + reader->record->header->NITF_UDHDL, \ + reader->record->header->NITF_UDHOFL, \ + error)) \ + goto CATCH_ERROR; + +/* This macro makes it easier to read the extended header */ +/* section. As above, the readExtras() method supplies */ +/* the underlying driving call, but it can be generalized */ +/* for this case, and for the user header components too */ +#define TRY_READ_XHD(reader_) \ + if (!readExtras(reader_, \ + reader->record->header->extendedSection, \ + reader->record->header->NITF_XHDL, \ + reader->record->header->NITF_XHDLOFL, \ + error)) \ + goto CATCH_ERROR; + +#define TRY_READ_UDID(reader_, imageIndex_, subhdr_) \ + if (!readExtras(reader_, \ + subhdr_->userDefinedSection, \ + subhdr_->NITF_UDIDL, \ + subhdr_->NITF_UDOFL, \ + error)) \ + goto CATCH_ERROR; + +#define TRY_READ_IXSHD(reader_, imageIndex_, subhdr_) \ + if (!readExtras(reader_, \ + subhdr_->extendedSection, \ + subhdr_->NITF_IXSHDL, \ + subhdr_->NITF_IXSOFL, \ + error)) \ + goto CATCH_ERROR; + +#define TRY_READ_SXSHD(reader_, graphicIndex_, subhdr_) \ + if (!readExtras(reader_, \ + subhdr_->extendedSection, \ + subhdr_->NITF_SXSHDL, \ + subhdr_->NITF_SXSOFL, \ + error)) \ + goto CATCH_ERROR; + +#define TRY_READ_LXSHD(reader_, labelIndex_, subhdr_) \ + if (!readExtras(reader_, \ + subhdr_->extendedSection, \ + subhdr_->NITF_LXSHDL, \ + subhdr_->NITF_LXSOFL, \ + error)) \ + goto CATCH_ERROR; + +#define TRY_READ_TXSHD(reader_, textIndex_, subhdr_) \ + if (!readExtras(reader_, \ + subhdr_->extendedSection, \ + subhdr_->NITF_TXSHDL, \ + subhdr_->NITF_TXSOFL, \ + error)) \ + goto CATCH_ERROR; + +/* These are internal macros which basically provide a */ +/* mock version of exceptions in C. They are simple */ +/* so just read them. Because they are internal, use */ +/* them at your own risk. */ +/* */ +/* ASSUMPTIONS: */ +/* 1) An instance of a NITF_BOOL named success exists, */ +/* and can be overwritten by the macros. */ +/* 2) A label is in scope called CATCH_ERROR */ + +#define TRY_READ_VALUE(reader_, field_, length_) \ + if (!readValue(reader_, field_, length_, error)) goto CATCH_ERROR; + +#define TRY_READ_MEMBER_VALUE(reader_, OWNER, ID) \ + if (!readValue(reader_, OWNER->ID, ID##_SZ, error)) goto CATCH_ERROR; + +#define TRY_READ_COMPONENT(reader_, infoPtrPtr_, numValue_, \ + subHdrSz_, dataSz_) \ +if (!readComponentInfo(reader_, \ + infoPtrPtr_, \ + numValue_, \ + subHdrSz_, \ + dataSz_, \ + error) ) goto CATCH_ERROR; + +/* This is the size of each num* (numi, numx, nums, numdes, numres) */ +#define NITF_IVAL_SZ 3 + +NITFPRIV(nitf_BandInfo **) readBandInfo(nitf_Reader * reader, + unsigned int nbands, + nitf_Error * error); + +NITFPRIV(NITF_BOOL) readCorners(nitf_Reader * reader, + nitf_ImageSubheader * subhdr, + nitf_Version fver, nitf_Error * error); + +NITFPRIV(NITF_BOOL) readTRE(nitf_Reader * reader, + nitf_Extensions * ext, nitf_Error * error); + +NITFPRIV(NITF_BOOL) readField(nitf_Reader * reader, + char *fld, int length, nitf_Error * error); + +NITFPRIV(NITF_BOOL) readValue(nitf_Reader * reader, + nitf_Field * field, + int length, nitf_Error * error); +NITFPRIV(NITF_BOOL) handleTRE(nitf_Reader * reader, nitf_Uint32 length, + nitf_TRE * tre, nitf_Error * error); + +/* This method reads the extra sections from the header, if */ +/* there _are_ any. If not, no big deal. */ +NITFPRIV(NITF_BOOL) readExtras(nitf_Reader * reader, + nitf_Extensions * ext, + nitf_Field * totalLengthValue, + nitf_Field * overflowOffsetValue, + nitf_Error * error); + +/* Reading the component info sections is not a big deal, but it does */ +/* suit us that we are interested in reuse. This method may be */ +/* used for all component info sections, however, we must be handed the */ +/* offset size, which will require a front-end macro. They are listed: */ +/* NITF_READ_IMAGE_INFO() */ +/* NITF_READ_GRAPHICS_INFO() */ +/* NITF_READ_TEXT_INFO() */ +/* NITF_READ_LABEL_INFO() */ +/* NITF_READ_DATA_EXT_INFO() */ +/* NITF_READ_RESERVED_EXT_INFO() */ +/* */ +/* \param reader The reader object */ +/* \param ioHandle The IO handle */ +/* \param infoPtr A pointer to the componentInfo object to be populated */ +/* \param num A value representing the number of components that existed */ +/* \param subHdrSz Size of the field describing subheader length */ +/* \param dataSz Size of the field describing the data length */ +/* \param error An error object to be populated on failure */ +/* \return NITF_SUCCESS on success and 0 otherwise */ +NITFPRIV(NITF_BOOL) readComponentInfo(nitf_Reader * reader, + nitf_ComponentInfo *** infoPtrPtr, + nitf_Field * numValue, + const int subHdrSz, + const int dataSz, nitf_Error * error) +{ + int i; + int numComponents; /* Total number of components */ + + /* Read the number of components */ + TRY_READ_VALUE(reader, numValue, NITF_IVAL_SZ); + + /* Make sure it is a positive integer */ + NITF_TRY_GET_UINT32(numValue, &numComponents, error); + + /* Save ourselves some time if there is nothing in this section */ + /* NOTE: this should be the case for the label segment if NITF 2.1 */ + if (!numComponents) + { + *infoPtrPtr = NULL; + return NITF_SUCCESS; + } + + /* Malloc enough space for N image info nodes */ + *infoPtrPtr = (nitf_ComponentInfo **) + NITF_MALLOC(sizeof(nitf_ComponentInfo *) * numComponents); + + if (!*infoPtrPtr) + { + nitf_Error_init(error, + NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + return NITF_FAILURE; + } + + /* Read the image info */ + for (i = 0; i < numComponents; i++) + { + (*infoPtrPtr)[i] = nitf_ComponentInfo_construct(subHdrSz, + dataSz, error); + TRY_READ_VALUE(reader, + (*infoPtrPtr)[i]->lengthSubheader, subHdrSz); + + TRY_READ_VALUE(reader, (*infoPtrPtr)[i]->lengthData, dataSz); + } + return NITF_SUCCESS; + +CATCH_ERROR: + *infoPtrPtr = NULL; + return NITF_FAILURE; +} + + +/* This is a simple read method. Note that this is NOT a finalized */ +/* method. */ +NITFPRIV(NITF_BOOL) readField(nitf_Reader * reader, + char *fld, int length, nitf_Error * error) +{ + /* Make sure the field is nulled out */ + memset(fld, 0, length); + + /* Read from the IO handle */ + if (!nitf_IOInterface_read(reader->input, fld, length, error)) + { + nitf_Error_init(error, + "Unable to read from IO object", + NITF_CTXT, NITF_ERR_READING_FROM_FILE); + goto CATCH_ERROR; + } + + return NITF_SUCCESS; + +CATCH_ERROR: + return NITF_FAILURE; +} + + +NITFPRIV(NITF_BOOL) readValue(nitf_Reader * reader, + nitf_Field * field, + int length, nitf_Error * error) +{ + char *buf = (char *) NITF_MALLOC(length); + if (!buf) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + goto CATCH_ERROR; + } + + if (!readField(reader, buf, length, error)) + goto CATCH_ERROR; + + /* first, check to see if we need to swap bytes */ + if (field->type == NITF_BINARY) + { + if (length == NITF_INT16_SZ) + { + nitf_Int16 int16 = + (nitf_Int16)NITF_NTOHS(*((nitf_Int16 *) buf)); + if (!nitf_Field_setRawData(field, + (NITF_DATA *) & int16, length, error)) + goto CATCH_ERROR; + } + else if (length == NITF_INT32_SZ) + { + nitf_Int32 int32 = + (nitf_Int32)NITF_NTOHL(*((nitf_Int32 *) buf)); + if (!nitf_Field_setRawData(field, + (NITF_DATA *) & int32, length, error)) + goto CATCH_ERROR; + } + else + { + /* TODO what to do??? 8 bit is ok, but what about 64? */ + if (!nitf_Field_setRawData(field, (NITF_DATA *) buf, length, error)) + goto CATCH_ERROR; + } + } + else + { + if (!nitf_Field_setRawData(field, (NITF_DATA *) buf, length, error)) + goto CATCH_ERROR; + } + + NITF_FREE(buf); + return NITF_SUCCESS; + +CATCH_ERROR: + if (buf) NITF_FREE(buf); + return NITF_FAILURE; +} + + +/* This function reads the whole security section from a v2.0 (sub)header */ +NITFPRIV(NITF_BOOL) read20FileSecurity(nitf_Reader * reader, + nitf_FileSecurity * securityGroup, + nitf_Error * error) +{ + /* NOTE: The sizes are different from those of 2.1 */ + nitf_FileSecurity_resizeForVersion(securityGroup, NITF_VER_20, error); + + TRY_READ_VALUE(reader, securityGroup->NITF_CODE, NITF_CODE_20_SZ); + TRY_READ_VALUE(reader, securityGroup->NITF_CTLH, NITF_CTLH_20_SZ); + TRY_READ_VALUE(reader, securityGroup->NITF_REL, NITF_REL_20_SZ); + TRY_READ_VALUE(reader, securityGroup->NITF_CAUT, NITF_CAUT_20_SZ); + TRY_READ_VALUE(reader, securityGroup->NITF_CTLN, NITF_CTLN_20_SZ); + TRY_READ_VALUE(reader, securityGroup->NITF_DGDT, NITF_DGDT_20_SZ); + /* !!! fix century on date? */ + + if (!strncmp(securityGroup->NITF_DGDT->raw, "999998", 6)) + { + TRY_READ_VALUE(reader, securityGroup->NITF_CLTX, NITF_CLTX_20_SZ); + /* !!! fix century on date? */ + } + + return NITF_SUCCESS; + +CATCH_ERROR: + return NITF_FAILURE; +} + + +/* This function reads the whole file security section */ +/* using the NITF_READ_FIELD() macro. The macro takes */ +/* advantage of the naming conventions to read the */ +/* data with very little effort in calling. If you */ +/* dont like this kind of abstraction, you are welcome */ +/* to be more rigorous and expand out the macro. */ +NITFPRIV(NITF_BOOL) read21FileSecurity(nitf_Reader * reader, + nitf_FileSecurity * securityGroup, + nitf_Error * error) +{ + TRY_READ_MEMBER_VALUE(reader, securityGroup, NITF_CLSY); + TRY_READ_MEMBER_VALUE(reader, securityGroup, NITF_CODE); + TRY_READ_MEMBER_VALUE(reader, securityGroup, NITF_CTLH); + TRY_READ_MEMBER_VALUE(reader, securityGroup, NITF_REL); + TRY_READ_MEMBER_VALUE(reader, securityGroup, NITF_DCTP); + TRY_READ_MEMBER_VALUE(reader, securityGroup, NITF_DCDT); + TRY_READ_MEMBER_VALUE(reader, securityGroup, NITF_DCXM); + TRY_READ_MEMBER_VALUE(reader, securityGroup, NITF_DG); + TRY_READ_MEMBER_VALUE(reader, securityGroup, NITF_DGDT); + TRY_READ_MEMBER_VALUE(reader, securityGroup, NITF_CLTX); + TRY_READ_MEMBER_VALUE(reader, securityGroup, NITF_CATP); + TRY_READ_MEMBER_VALUE(reader, securityGroup, NITF_CAUT); + TRY_READ_MEMBER_VALUE(reader, securityGroup, NITF_CRSN); + TRY_READ_MEMBER_VALUE(reader, securityGroup, NITF_RDT); + TRY_READ_MEMBER_VALUE(reader, securityGroup, NITF_CTLN); + + return NITF_SUCCESS; + +CATCH_ERROR: + return NITF_FAILURE; +} + + +/* This function reads a security section */ +NITFPRIV(NITF_BOOL) readFileSecurity(nitf_Reader * reader, + nitf_Version fver, + nitf_FileSecurity * securityGroup, + nitf_Error * error) +{ + if (IS_NITF20(fver)) + { + if (!read20FileSecurity(reader, securityGroup, error)) + goto CATCH_ERROR; + } + else if (IS_NITF21(fver)) + { + if (!read21FileSecurity(reader, securityGroup, error)) + goto CATCH_ERROR; + } + else + { + /* Invalid NITF Version (We had better never get here) */ + nitf_Error_init(error, "Invalid NITF Version", + NITF_CTXT, NITF_ERR_INVALID_FILE); + goto CATCH_ERROR; + } + + return NITF_SUCCESS; + +CATCH_ERROR: + return NITF_FAILURE; +} + + +NITFPRIV(void) resetIOInterface(nitf_Reader * reader) +{ + if (reader->input && reader->ownInput) + nitf_IOInterface_destruct( &(reader->input) ); + reader->input = NULL; + reader->ownInput = 0; +} + + +NITFAPI(nitf_Reader *) nitf_Reader_construct(nitf_Error * error) +{ + /* Create the reader */ + nitf_Reader *reader = (nitf_Reader *) NITF_MALLOC(sizeof(nitf_Reader)); + + /* If we have problems, populate the error object */ + if (!reader) + { + nitf_Error_init(error, + NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + return NULL; + } + + reader->warningList = nitf_List_construct(error); + if (!reader->warningList) + { + nitf_Reader_destruct(&reader); + return NULL; + } + + reader->record = NULL; + reader->input = NULL; + reader->ownInput = 0; + resetIOInterface(reader); + + /* Return our results */ + return reader; +} + + +NITFAPI(void) nitf_Reader_destruct(nitf_Reader ** reader) +{ + /* If the reader has already been destructed, or was never */ + /* Inited, dont dump core */ + if (*reader) + { + nitf_ListIterator iter; + nitf_ListIterator end; + if ((*reader)->warningList) + { + iter = nitf_List_begin((*reader)->warningList); + end = nitf_List_end((*reader)->warningList); + + while (nitf_ListIterator_notEqualTo(&iter, &end)) + { + nitf_FieldWarning *warning = + (nitf_FieldWarning *) nitf_ListIterator_get(&iter); + nitf_FieldWarning_destruct(&warning); + nitf_List_remove((*reader)->warningList, &iter); + } + nitf_List_destruct(&(*reader)->warningList); + } + /* + if ((*reader)->imageReaderPool) + { + iter = nitf_List_begin( (*reader)->imageReaderPool ); + end = nitf_List_end( (*reader)->imageReaderPool ); + + while (nitf_ListIterator_notEqualTo(&iter, &end)) + { + nitf_ImageReader* imageReader = + (nitf_ImageReader*)nitf_ListIterator_get(&iter); + + nitf_ImageReader_destruct(& imageReader ); + nitf_ListIterator_increment(&iter); + } + + nitf_List_destruct( & (*reader)->imageReaderPool ); + + } + */ + + /* this will delete the input if we own it */ + resetIOInterface(*reader); + + (*reader)->warningList = NULL; + (*reader)->record = NULL; + + NITF_FREE(*reader); + *reader = NULL; + } +} + + +NITFPRIV(NITF_BOOL) readImageSubheader(nitf_Reader * reader, + unsigned int imageIndex, + nitf_Version fver, + nitf_Error * error) +{ + unsigned int i; + nitf_ImageSubheader *subhdr; + /* List iterator pointing to the image segment */ + nitf_ListIterator listIter = nitf_List_begin(reader->record->images); + + nitf_Uint32 numComments; /* Number of comment fields */ + nitf_Uint32 nbands; /* An integer representing the \nbands field */ + nitf_Uint32 xbands; /* An integer representing the xbands field */ + + for (i = 0; i < imageIndex; i++) + nitf_ListIterator_increment(&listIter); + + /* image sub-header object */ + subhdr = + ((nitf_ImageSegment *) nitf_ListIterator_get(&listIter))-> + subheader; + + /* If this isn't IM, is there something we can do? */ + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_IM); + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_IID1); + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_IDATIM); + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_TGTID); + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_IID2); + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_ISCLAS); + + /* Read the security group */ + if (!readFileSecurity(reader, fver, subhdr->securityGroup, error)) + goto CATCH_ERROR; + + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_ENCRYP); + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_ISORCE); + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_NROWS); + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_NCOLS); + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_PVTYPE); + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_IREP); + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_ICAT); + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_ABPP); + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_PJUST); + + /* Read the ICORDS and IGEOLO segments */ + if (!readCorners(reader, subhdr, fver, error)) + goto CATCH_ERROR; + + /* Figure out how many comments we have */ + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_NICOM); + NITF_TRY_GET_UINT32(subhdr->numImageComments, &numComments, error); + for (i = 0; i < numComments; i++) + { + nitf_Field* commentField = nitf_Field_construct( + NITF_ICOM_SZ, NITF_BCS_A, error); + if (!commentField) goto CATCH_ERROR; + TRY_READ_VALUE(reader, commentField, NITF_ICOM_SZ); + nitf_List_pushBack(subhdr->imageComments, commentField, error); + } + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_IC); + + if (strncmp(subhdr->NITF_IC->raw, "NC", 2) != 0 && + strncmp(subhdr->NITF_IC->raw, "NM", 2) != 0) + { + + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_COMRAT); + } + /* Figure out how many bands */ + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_NBANDS); + xbands = 0; + + /* In NITF versions before 2.1, the number of bands was a single + digit 1-9, because the designers were not thinking of + multi/hyperspectral images. So the multispectral folk put a 0 + in numbands and put the real number of bands in a BANDSA SDE. + So, version 2.1 legalized this hack, but put in a larger field + (conditionally) so the actual number of bands could be put in + the image subheader, where it belongs. Sheesh! + */ + /* !!! note we do not handle the ver2.0 case where true nbands only + in BANDSA */ + NITF_TRY_GET_UINT32(subhdr->numImageBands, &nbands, error); + if ((!nbands) && IS_NITF21(fver)) + { + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_XBANDS); + NITF_TRY_GET_UINT32(subhdr->numMultispectralImageBands, + &xbands, error); + } + nbands = nbands + xbands; + subhdr->bandInfo = readBandInfo(reader, (unsigned int) nbands, error); + + if (!subhdr->bandInfo) + { + /* Error, BandInfo is null */ + goto CATCH_ERROR; + } + + /* Afer we have read the band info, things are cool again for a bit */ + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_ISYNC); + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_IMODE); + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_NBPR); + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_NBPC); + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_NPPBH); + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_NPPBV); + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_NBPP); + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_IDLVL); + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_IALVL); + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_ILOC); + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_IMAG); + + /* Read the userd efined image data */ + TRY_READ_UDID(reader, imageIndex, subhdr); + /* Read the extended header info section */ + TRY_READ_IXSHD(reader, imageIndex, subhdr); + + return NITF_SUCCESS; + +CATCH_ERROR: + + return NITF_FAILURE; +} + + +NITFPRIV(NITF_BOOL) readGraphicSubheader(nitf_Reader * reader, + int graphicIndex, + nitf_Version fver, + nitf_Error * error) +{ + int i; + nitf_GraphicSubheader *subhdr; + + /* List iterator pointing to the graphics segment */ + nitf_ListIterator listIter = nitf_List_begin(reader->record->graphics); + for (i = 0; i < graphicIndex; i++) + nitf_ListIterator_increment(&listIter); + + /* graphics sub-header object */ + subhdr = ((nitf_GraphicSegment *) + nitf_ListIterator_get(&listIter))->subheader; + + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_SY); + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_SID); + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_SNAME); + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_SSCLAS); + + /* Read the security section */ + if (!readFileSecurity(reader, fver, subhdr->securityGroup, error)) + goto CATCH_ERROR; + + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_ENCRYP); + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_SFMT); + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_SSTRUCT); + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_SDLVL); + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_SALVL); + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_SLOC); + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_SBND1); + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_SCOLOR); + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_SBND2); + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_SRES2); + + /* Read the extended header info section */ + TRY_READ_SXSHD(reader, graphicIndex, subhdr); + + return NITF_SUCCESS; + +CATCH_ERROR: + + return NITF_FAILURE; +} + + +NITFPRIV(NITF_BOOL) readLabelSubheader(nitf_Reader * reader, + int labelIndex, + nitf_Version fver, + nitf_Error * error) +{ + int i; + nitf_LabelSubheader *subhdr; + + /* List iterator pointing to the label segment */ + nitf_ListIterator listIter = nitf_List_begin(reader->record->labels); + for (i = 0; i < labelIndex; i++) + nitf_ListIterator_increment(&listIter); + + /* label sub-header object */ + subhdr = + ((nitf_LabelSegment *) nitf_ListIterator_get(&listIter))-> + subheader; + + /* nitf_Uint32 lxshdl, lxsofl; */ + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_LA); + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_LID); + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_LSCLAS); + + /* Read the security group */ + if (!readFileSecurity(reader, fver, subhdr->securityGroup, error)) + goto CATCH_ERROR; + + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_ENCRYP); + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_LFS); + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_LCW); + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_LCH); + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_LDLVL); + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_LALVL); + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_LLOCR); + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_LLOCC); + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_LTC); + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_LBC); + + /* Read the extended header info section */ + TRY_READ_LXSHD(reader, labelIndex, subhdr); + + return NITF_SUCCESS; + +CATCH_ERROR: + + return NITF_FAILURE; +} + + +NITFPRIV(NITF_BOOL) readTextSubheader(nitf_Reader * reader, + int textIndex, + nitf_Version fver, + nitf_Error * error) +{ + int i; + nitf_TextSubheader *subhdr; + + /* List iterator pointing to the text segment */ + nitf_ListIterator listIter = nitf_List_begin(reader->record->texts); + for (i = 0; i < textIndex; i++) + nitf_ListIterator_increment(&listIter); + + /* text sub-header object */ + subhdr = + ((nitf_TextSegment *) nitf_ListIterator_get(&listIter))->subheader; + + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_TE); + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_TEXTID); + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_TXTALVL); + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_TXTDT); + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_TXTITL); + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_TSCLAS); + + /* Read the security group */ + if (!readFileSecurity(reader, fver, subhdr->securityGroup, error)) + goto CATCH_ERROR; + + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_ENCRYP); + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_TXTFMT); + + /* Read the extended header info section */ + TRY_READ_TXSHD(reader, textIndex, subhdr); + + return NITF_SUCCESS; + +CATCH_ERROR: + + return NITF_FAILURE; +} + + +NITFPRIV(NITF_BOOL) readDESubheader(nitf_Reader * reader, + int desIndex, + nitf_Version fver, nitf_Error * error) +{ + int i; + nitf_DESegment *segment; + nitf_DESubheader *subhdr; + /* Length of the sub-header */ + nitf_Uint32 subLen; + nitf_Off currentOffset; + char desID[NITF_DESTAG_SZ + 1]; /* DES ID string */ + + nitf_ListIterator listIter = + nitf_List_begin(reader->record->dataExtensions); + + for (i = 0; i < desIndex; i++) + nitf_ListIterator_increment(&listIter); + + /* get the correct objects */ + segment = (nitf_DESegment *) nitf_ListIterator_get(&listIter); + subhdr = segment->subheader; + + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_DE); + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_DESTAG); + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_DESVER); + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_DESCLAS); + + /* Read the security group */ + if (!readFileSecurity(reader, fver, subhdr->securityGroup, error)) + goto CATCH_ERROR; + + /* get the DESID and trim it */ + nitf_Field_get(subhdr->NITF_DESTAG, + desID, NITF_CONV_STRING, NITF_DESTAG_SZ + 1, error); + nitf_Field_trimString(desID); + + /* read the two conditional fields if TRE_OVERFLOW */ + if ((IS_NITF20(fver) && ((strcmp(desID, "Registered Extensions") == 0) || + (strcmp(desID, "Controlled Extensions") == 0))) || + (IS_NITF21(fver) && strcmp(desID, "TRE_OVERFLOW") == 0)) + { + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_DESOFLW); + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_DESITEM); + } + + /* get the subheaderfields length */ + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_DESSHL); + + /* Verify that it is a UINT */ + NITF_TRY_GET_UINT32(subhdr->NITF_DESSHL, &subLen, error); + if (subLen > 0) + { + /* We know our constraints, so build up the tre object */ + subhdr->subheaderFields = nitf_TRE_createSkeleton(desID, error); + + if (!subhdr->subheaderFields) + goto CATCH_ERROR; + + if (!handleTRE(reader, subLen, subhdr->subheaderFields, error)) + goto CATCH_ERROR; + } + + NITF_TRY_GET_UINT64(reader->record-> + header->dataExtensionInfo[desIndex]->lengthData, + &subhdr->dataLength, error); + + /* set the offset and end of the segment */ + segment->offset = nitf_IOInterface_tell(reader->input, error); + if (!NITF_IO_SUCCESS(segment->offset)) + goto CATCH_ERROR; + segment->end = segment->offset + subhdr->dataLength; + + /* see if we need to read the data now as part of a TRE */ + if ((strcmp(desID, "TRE_OVERFLOW") == 0) || + (strcmp(desID, "Controlled Extensions") == 0)) + { + currentOffset = segment->offset; + + /* loop until we are done */ + while (currentOffset < segment->end) + { + /* read a TRE */ + if (!readTRE(reader, subhdr->userDefinedSection, error)) + goto CATCH_ERROR; + + /* update the offset */ + currentOffset = nitf_IOInterface_tell(reader->input, error); + if (!NITF_IO_SUCCESS(currentOffset)) + goto CATCH_ERROR; + } + } + else + { + /* seek past the data for now */ + if (!NITF_IO_SUCCESS(nitf_IOInterface_seek(reader->input, + segment->end, NITF_SEEK_SET, + error))) + { + goto CATCH_ERROR; + } + } + + return NITF_SUCCESS; + +CATCH_ERROR: + return NITF_FAILURE; +} + + +NITFPRIV(NITF_BOOL) readRESubheader(nitf_Reader * reader, + int resIndex, + nitf_Version fver, nitf_Error * error) +{ + int i; + nitf_RESegment *segment; + nitf_RESubheader *subhdr; + nitf_Uint32 subLen; + /* List iterator pointing to the reserved extension segment */ + nitf_ListIterator listIter = + nitf_List_begin(reader->record->reservedExtensions); + + for (i = 0; i < resIndex; i++) + nitf_ListIterator_increment(&listIter); + + /* RE objects */ + segment = (nitf_RESegment *) nitf_ListIterator_get(&listIter); + subhdr = segment->subheader; + + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_RE); + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_RESTAG); + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_RESVER); + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_RESCLAS); + + /* Read the security group */ + if (!readFileSecurity(reader, fver, subhdr->securityGroup, error)) + goto CATCH_ERROR; + + /* get the subheader fields length */ + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_RESSHL); + NITF_TRY_GET_UINT32(subhdr->subheaderFieldsLength, &subLen, error); + if (subLen > 0) + { + /* for now, we just read it into a buffer... change in the future */ + if (!readField(reader, subhdr->subheaderFields, subLen, error)) + goto CATCH_ERROR; + } + + /* now, we will just zoom past the data, if any */ + NITF_TRY_GET_UINT64(reader->record-> + header->reservedExtensionInfo[resIndex]-> + lengthData, &subhdr->dataLength, error); + + /* set the offset and end of the segment */ + segment->offset = nitf_IOInterface_tell(reader->input, error); + if (!NITF_IO_SUCCESS(segment->offset)) + goto CATCH_ERROR; + segment->end = segment->offset + subhdr->dataLength; + + return NITF_SUCCESS; + +CATCH_ERROR: + + return NITF_FAILURE; +} + + +/* This function reads the whole file header section */ +/* using the READ_HDR_FIELD() macro. The macro takes */ +/* advantage of the naming conventions to read the */ +/* data with very little effort in calling. If you */ +/* dont like this kind of abstraction, you are welcome */ +/* to be more rigorous and expand out the macro. */ +/* */ +/* It also then reads the sections beneath, one by one. */ +/* HELP!!!!! Someone beef up these comments, and get the .h file up to snuff */ +NITFPRIV(NITF_BOOL) readHeader(nitf_Reader * reader, nitf_Error * error) +{ + /* Pointer to the fileHeade, simplifies futher references to this object */ + nitf_FileHeader *fileHeader = reader->record->header; + + /* generic uint32 */ + nitf_Uint32 num32; + + nitf_Version fver; + /*nitf_Uint32 udhdl, udhofl, xhdl, xhdlofl; */ + + char fileLenBuf[NITF_FL_SZ + 1]; /* File length buffer */ + char streamingBuf[NITF_FL_SZ]; + + /* FHDR */ + TRY_READ_MEMBER_VALUE(reader, fileHeader, NITF_FHDR); + if ((strncmp(fileHeader->NITF_FHDR->raw, "NITF", 4) != 0) + && (strncmp(fileHeader->NITF_FHDR->raw, "NSIF", 4) != 0)) + { + nitf_Error_init(error, + "File does not appear to be NITF", + NITF_CTXT, NITF_ERR_INVALID_FILE); + goto CATCH_ERROR; + } + + /* FVER */ + TRY_READ_MEMBER_VALUE(reader, fileHeader, NITF_FVER); + + fver = nitf_Record_getVersion(reader->record); + if (!IS_NITF20(fver) && !IS_NITF21(fver)) + { + nitf_Error_init(error, + "Unknown NITF version", + NITF_CTXT, NITF_ERR_PARSING_FILE); + goto CATCH_ERROR; + } + + TRY_READ_MEMBER_VALUE(reader, fileHeader, NITF_CLEVEL); + TRY_READ_MEMBER_VALUE(reader, fileHeader, NITF_STYPE); + TRY_READ_MEMBER_VALUE(reader, fileHeader, NITF_OSTAID); + TRY_READ_MEMBER_VALUE(reader, fileHeader, NITF_FDT); + TRY_READ_MEMBER_VALUE(reader, fileHeader, NITF_FTITLE); + TRY_READ_MEMBER_VALUE(reader, fileHeader, NITF_FSCLAS); + + if (!readFileSecurity(reader, fver, fileHeader->securityGroup, error)) + goto CATCH_ERROR; + + TRY_READ_MEMBER_VALUE(reader, fileHeader, NITF_FSCOP); + TRY_READ_MEMBER_VALUE(reader, fileHeader, NITF_FSCPYS); + TRY_READ_MEMBER_VALUE(reader, fileHeader, NITF_ENCRYP); + + /* In 2.0 there wasn't a FBKGC field, so we resize ONAME and read */ + if (IS_NITF20(fver)) + { + if (!nitf_Field_resetLength(fileHeader->NITF_ONAME, + NITF_FBKGC_SZ + NITF_ONAME_SZ, 0, error)) + goto CATCH_ERROR; + + if (!readValue(reader, fileHeader->NITF_ONAME, + NITF_FBKGC_SZ + NITF_ONAME_SZ, error)) + goto CATCH_ERROR; + } + else + { + TRY_READ_MEMBER_VALUE(reader, fileHeader, NITF_FBKGC); + TRY_READ_MEMBER_VALUE(reader, fileHeader, NITF_ONAME); + } + TRY_READ_MEMBER_VALUE(reader, fileHeader, NITF_OPHONE); + + /* FL */ + TRY_READ_MEMBER_VALUE(reader, fileHeader, NITF_FL); + /* Check for streaming header (Length is all 9's) */ + memset(streamingBuf, '9', NITF_FL_SZ); + + nitf_Field_get(fileHeader->NITF_FL, + fileLenBuf, NITF_CONV_STRING, NITF_FL_SZ + 1, error); + if (strncmp(fileLenBuf, streamingBuf, NITF_FL_SZ) == 0) + { + nitf_Error_init(error, "Streaming headers are not supported", + NITF_CTXT, NITF_ERR_PARSING_FILE); + goto CATCH_ERROR; + } + + /* HL */ + TRY_READ_MEMBER_VALUE(reader, fileHeader, NITF_HL); + NITF_TRY_GET_UINT32(fileHeader->NITF_HL, &num32, error); + + /* Read the image info section */ + TRY_READ_COMPONENT(reader, + &fileHeader->imageInfo, + fileHeader->NITF_NUMI, NITF_LISH_SZ, NITF_LI_SZ); + + /* Read the graphic info section */ + TRY_READ_COMPONENT(reader, + &fileHeader->graphicInfo, + fileHeader->NITF_NUMS, NITF_LSSH_SZ, NITF_LS_SZ); + + /* Read the label info section */ + TRY_READ_COMPONENT(reader, + &fileHeader->labelInfo, + fileHeader->NITF_NUMX, NITF_LLSH_SZ, NITF_LL_SZ); + + /* Read the text info section */ + TRY_READ_COMPONENT(reader, + &fileHeader->textInfo, + fileHeader->NITF_NUMT, NITF_LTSH_SZ, NITF_LT_SZ); + + /* Read the data extension info section */ + TRY_READ_COMPONENT(reader, + &fileHeader->dataExtensionInfo, + fileHeader->NITF_NUMDES, NITF_LDSH_SZ, NITF_LD_SZ); + + /* Read the reserved extension info section */ + TRY_READ_COMPONENT(reader, + &fileHeader->reservedExtensionInfo, + fileHeader->NITF_NUMRES, + NITF_LRESH_SZ, NITF_LRE_SZ); + + /* Read the user header info section */ + TRY_READ_UDHD(reader); + + /* Read the extended header info section */ + TRY_READ_XHD(reader); + + return NITF_SUCCESS; + +CATCH_ERROR: + return NITF_FAILURE; +} + + +/* This function is quite possibly, not even right, except */ +/* I dont have any data that proves that it doesnt work. */ +/* Someone who knows better should fix this, because Im not */ +/* even convinced that it does the right thing. */ +/* Check to see if headerFieldSize and offsetFieldSize are always the same */ +NITFPRIV(NITF_BOOL) readExtras(nitf_Reader * reader, + nitf_Extensions * ext, + nitf_Field * totalLengthValue, + nitf_Field * overflowOffsetValue, + nitf_Error * error) +{ + /* Total length of the extras seciton */ + nitf_Uint32 totalLength; + /* Offset in the stream to the end of the section */ + nitf_Off sectionEndOffset; + /* The current io offset */ + nitf_Off currentOffset; + + /* Read the total length of the "extras" section */ + TRY_READ_VALUE(reader, totalLengthValue, 5); + + /* Make sure it is a positive integer */ + NITF_TRY_GET_UINT32(totalLengthValue, &totalLength, error); + + if (totalLength) + { + /* Read the overflowOffset */ + TRY_READ_VALUE(reader, overflowOffsetValue, 3); + + currentOffset = nitf_IOInterface_tell(reader->input, error); + if (!NITF_IO_SUCCESS(currentOffset)) + goto CATCH_ERROR; + + sectionEndOffset = currentOffset + (nitf_Off) totalLength - 3; + + while (currentOffset < sectionEndOffset) + { + if (!readTRE(reader, ext, error)) + { + nitf_FieldWarning *fieldWarning; + /* Get the current offset */ + currentOffset = nitf_IOInterface_tell(reader->input, + error); + + if (!NITF_IO_SUCCESS(currentOffset)) + goto CATCH_ERROR; + + /* Generate a warning */ + fieldWarning = + nitf_FieldWarning_construct(currentOffset, + "TRE", + NULL, + "Not properly formed", + error); + if (fieldWarning == NULL) + goto CATCH_ERROR; + + /* Append the warning to the list */ + if (!nitf_List_pushBack + (reader->warningList, fieldWarning, error)) + { + goto CATCH_ERROR; + } + + /* Skip the remaining TRE's */ + currentOffset = + nitf_IOInterface_seek(reader->input, + sectionEndOffset - currentOffset, + NITF_SEEK_CUR, error); + if (!NITF_IO_SUCCESS(currentOffset)) + goto CATCH_ERROR; + } + + currentOffset = nitf_IOInterface_tell(reader->input, error); + if (!NITF_IO_SUCCESS(currentOffset)) + goto CATCH_ERROR; + + } /* End of while */ + } + + /* no problems */ + return NITF_SUCCESS; + +CATCH_ERROR: + return NITF_FAILURE; +} + + +NITFPRIV(NITF_BOOL) readTRE(nitf_Reader * reader, + nitf_Extensions * ext, + nitf_Error * error) +{ + /* character array for the tag */ + char etag[NITF_ETAG_SZ + 1]; + + /* tre object */ + nitf_TRE *tre; + + /* length of the TRE object */ + nitf_Uint32 length; + nitf_Field *lengthValue; + + memset(etag, 0, NITF_ETAG_SZ + 1); + + /* A value to store the length in + (we really just want the nice conversion functions ) */ + lengthValue = nitf_Field_construct(NITF_EL_SZ, NITF_BCS_N, error); + if (!lengthValue) + goto CATCH_ERROR; + + /* Read the tag header */ + if (!readField(reader, etag, NITF_ETAG_SZ, error)) + goto CATCH_ERROR; + + /* blank trim the tag */ + nitf_Field_trimString(etag); + + TRY_READ_VALUE(reader, lengthValue, NITF_EL_SZ); + NITF_TRY_GET_UINT32(lengthValue, &length, error); + + /* We know our constraints, so build up the tre object */ + tre = nitf_TRE_createSkeleton(etag, error); + if (!tre) + goto CATCH_ERROR; + + if (!handleTRE(reader, length, tre, error)) + goto CATCH_ERROR; + + /* Insert the tre into the data store */ + if (!nitf_Extensions_appendTRE(ext, tre, error)) + goto CATCH_ERROR; + + /* Destruct the value object we created */ + nitf_Field_destruct(&lengthValue); + lengthValue = NULL; + + return NITF_SUCCESS; + +CATCH_ERROR: + /* Destruct the value object we created */ + if (lengthValue) nitf_Field_destruct(&lengthValue); + if (tre) nitf_TRE_destruct(&tre); + return NITF_FAILURE; +} + + +NITFPRIV(NITF_BOOL) handleTRE(nitf_Reader * reader, nitf_Uint32 length, + nitf_TRE * tre, nitf_Error * error) +{ + int ok = 0; + int bad = 0; + nitf_Off off; + + nitf_TREHandler* handler = NULL; + + nitf_PluginRegistry *reg = nitf_PluginRegistry_getInstance(error); + if (reg) + { + handler = nitf_PluginRegistry_retrieveTREHandler(reg, tre->tag, + &bad, error); + if (bad) + goto CATCH_ERROR; + if (handler) + { + tre->handler = handler; + off = nitf_IOInterface_tell(reader->input, error); + + ok = handler->read(reader->input, length, tre, + reader->record, error); + if (!ok) + { + /* move the IO back the size of the TRE */ + nitf_IOInterface_seek(reader->input, off, NITF_SEEK_SET, error); + } + } + } + + /* if we couldn't parse it with the plug-in OR if no plug-in is found, + * then, we use the default TRE handler */ + if (!ok || handler == NULL) + { + tre->handler = nitf_DefaultTRE_handler(error); + ok = tre->handler->read(reader->input, length, tre, + reader->record, error); + } + + if (!ok) + goto CATCH_ERROR; + + /* no problems */ + return NITF_SUCCESS; + +CATCH_ERROR: + return NITF_FAILURE; +} + + +NITFPRIV(NITF_BOOL) readCorners(nitf_Reader * reader, + nitf_ImageSubheader * subhdr, + nitf_Version fver, nitf_Error * error) +{ + + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_ICORDS); + + if ((IS_NITF20(fver) && + (subhdr->NITF_ICORDS->raw[0] == 'U' || + subhdr->NITF_ICORDS->raw[0] == 'G' || + subhdr->NITF_ICORDS->raw[0] == 'C')) + || + ((IS_NITF21(fver) && + (subhdr->NITF_ICORDS->raw[0] == 'U' || + subhdr->NITF_ICORDS->raw[0] == 'G' || + subhdr->NITF_ICORDS->raw[0] == 'N' || + subhdr->NITF_ICORDS->raw[0] == 'S' || + subhdr->NITF_ICORDS->raw[0] == 'D')))) + { + TRY_READ_MEMBER_VALUE(reader, subhdr, NITF_IGEOLO); + } + else + { + /*printf("Note to programmer: there was no IGEOLO place in the file\n"); */ + } + + return NITF_SUCCESS; + +CATCH_ERROR: + + return NITF_FAILURE; + +} + + +NITFPRIV(nitf_BandInfo **) readBandInfo(nitf_Reader * reader, + unsigned int nbands, + nitf_Error * error) +{ + nitf_Uint32 i; + nitf_Uint32 numLuts, bandEntriesPerLut; + nitf_BandInfo **bandInfo = NULL; + if (nbands > 0) + { + bandInfo = + (nitf_BandInfo **) NITF_MALLOC(sizeof(nitf_BandInfo *) * + nbands); + if (!bandInfo) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + return NULL; + } + } + + /* Make sure we are all NULL-inited */ + for (i = 0; i < nbands; i++) + bandInfo[i] = nitf_BandInfo_construct(error); + + /* Now pick up our precious band info */ + for (i = 0; i < nbands; i++) + { + TRY_READ_MEMBER_VALUE(reader, bandInfo[i], NITF_IREPBAND); + TRY_READ_MEMBER_VALUE(reader, bandInfo[i], NITF_ISUBCAT); + TRY_READ_MEMBER_VALUE(reader, bandInfo[i], NITF_IFC); + TRY_READ_MEMBER_VALUE(reader, bandInfo[i], NITF_IMFLT); + + TRY_READ_MEMBER_VALUE(reader, bandInfo[i], NITF_NLUTS); + NITF_TRY_GET_UINT32(bandInfo[i]->NITF_NLUTS, &numLuts, error); + if (numLuts > 0) + { + TRY_READ_MEMBER_VALUE(reader, bandInfo[i], NITF_NELUT); + NITF_TRY_GET_UINT32(bandInfo[i]->NITF_NELUT, + &bandEntriesPerLut, error); + + bandInfo[i]->lut = nitf_LookupTable_construct(numLuts, + bandEntriesPerLut, + error); + if (!bandInfo[i]->lut) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + return NULL; + } + if (!readField(reader, (char *) bandInfo[i]->lut->table, + numLuts * bandEntriesPerLut, error)) + goto CATCH_ERROR; + } + } + return bandInfo; + +CATCH_ERROR: + return NULL; +} + + +NITFAPI(nitf_Record *) nitf_Reader_read(nitf_Reader * reader, + nitf_IOHandle ioHandle, + nitf_Error * error) +{ + nitf_Record *record = NULL; + nitf_IOInterface *io = NULL; + + io = nitf_IOHandleAdapter_construct(ioHandle, NRT_ACCESS_READONLY, error); + if (!io) + return NULL; + + record = nitf_Reader_readIO(reader, io, error); + reader->ownInput = 1; /* we own the IOInterface */ + return record; +} + + +NITFAPI(nitf_Record *) nitf_Reader_readIO(nitf_Reader* reader, + nitf_IOInterface* io, + nitf_Error* error) +{ + nitf_Uint32 i = 0; /* iterator */ + nitf_Uint32 num32; /* generic uint32 */ + nitf_Uint32 length32; + nitf_Uint64 length; + nitf_Version fver; + + reader->record = nitf_Record_construct(NITF_VER_21, error); + if (!reader->record) + { + /* Couldnt make a record */ + return NULL; + } + + resetIOInterface(reader); + reader->input = io; + if (!reader->input) + goto CATCH_ERROR; + + /* This part is trivial thanks to our readHeader accessor */ + if (!readHeader(reader, error)) + goto CATCH_ERROR; + + fver = nitf_Record_getVersion(reader->record); + NITF_TRY_GET_UINT32(reader->record->header->numImages, &num32, error); + + /* Foreach image, read the header and skip to the end */ + for (i = 0; i < num32; i++) + { + /* Construct a new segment */ + nitf_ImageSegment *imageSegment = + nitf_ImageSegment_construct(error); + if (!imageSegment) + goto CATCH_ERROR; + + /* Push it onto the back of the list of segments */ + if (!nitf_List_pushBack(reader->record->images, + (NITF_DATA *) imageSegment, error)) + { + nitf_ImageSegment_destruct(&imageSegment); + goto CATCH_ERROR; + } + + /* Read the sub-header */ + if (!readImageSubheader(reader, i, fver, error)) + goto CATCH_ERROR; + + /* Allocate an IO object */ + imageSegment->imageOffset = nitf_IOInterface_tell(reader->input, + error); + + /* For now, we mark this as imageOffset + length of image data */ + NITF_TRY_GET_UINT64(reader->record->header->NITF_LI(i), + &length, error); + imageSegment->imageEnd = imageSegment->imageOffset + length; + + /* Now, we zoom to the end of the image, so we can pick up */ + /* afterward. */ + if (!NITF_IO_SUCCESS(nitf_IOInterface_seek(reader->input, + imageSegment->imageEnd, + NITF_SEEK_SET, error))) + { + goto CATCH_ERROR; + } + } + + NITF_TRY_GET_UINT32(reader->record->header->numGraphics, + &num32, + error); + + for (i = 0; i < num32; i++) + { + /* Construct a new segment */ + nitf_GraphicSegment *graphicSegment = + nitf_GraphicSegment_construct(error); + + if (!graphicSegment) + goto CATCH_ERROR; + + /* Push it onto the back of the list of segments */ + if (!nitf_List_pushBack(reader->record->graphics, + (NITF_DATA *) graphicSegment, error)) + { + nitf_GraphicSegment_destruct(&graphicSegment); + goto CATCH_ERROR; + } + + if (!readGraphicSubheader(reader, i, fver, error)) + goto CATCH_ERROR; + graphicSegment->offset = nitf_IOInterface_tell(reader->input, + error); + + /* For now, we mark this as graphicOffset + length of graphic data */ + NITF_TRY_GET_UINT32(reader->record->header->NITF_LS(i), + &length32, error); + + graphicSegment->end = graphicSegment->offset + length32; + + /* Now, we zoom to the end of the graphic, so we can pick up */ + /* afterward. */ + if (!NITF_IO_SUCCESS(nitf_IOInterface_seek(reader->input, + graphicSegment->end, + NITF_SEEK_SET, error))) + { + goto CATCH_ERROR; + } + } + + NITF_TRY_GET_UINT32(reader->record->header->numLabels, &num32, error); + for (i = 0; i < num32; i++) + { + /* Construct a new segment */ + nitf_LabelSegment *labelSegment = + nitf_LabelSegment_construct(error); + if (!labelSegment) + goto CATCH_ERROR; + + /* Push it onto the back of the list of segments */ + if (!nitf_List_pushBack(reader->record->labels, + (NITF_DATA *) labelSegment, error)) + { + nitf_LabelSegment_destruct(&labelSegment); + goto CATCH_ERROR; + } + + if (!readLabelSubheader(reader, i, fver, error)) + goto CATCH_ERROR; + labelSegment->offset = nitf_IOInterface_tell(reader->input, + error); + + /* For now, we mark this as labelOffset + length of label data */ + NITF_TRY_GET_UINT32(reader->record->header->NITF_LL(i), + &length32, error); + labelSegment->end = labelSegment->offset + length32; + + /* Now, we zoom to the end of the label, so we can pick up */ + /* afterward. */ + if (!NITF_IO_SUCCESS(nitf_IOInterface_seek(reader->input, + labelSegment->end, + NITF_SEEK_SET, error))) + { + goto CATCH_ERROR; + } + } + + NITF_TRY_GET_UINT32(reader->record->header->numTexts, &num32, error); + for (i = 0; i < num32; i++) + { + /* Construct a new segment */ + nitf_TextSegment *textSegment = nitf_TextSegment_construct(error); + if (!textSegment) + goto CATCH_ERROR; + + /* Push it onto the back of the list of segments */ + if (!nitf_List_pushBack(reader->record->texts, + (NITF_DATA *) textSegment, error)) + { + nitf_TextSegment_destruct(&textSegment); + goto CATCH_ERROR; + } + + if (!readTextSubheader(reader, i, fver, error)) + goto CATCH_ERROR; + textSegment->offset = nitf_IOInterface_tell(reader->input, + error); + + /* For now, we mark this as textOffset + length of text data */ + NITF_TRY_GET_UINT32(reader->record->header->NITF_LT(i), + &length32, error); + textSegment->end = textSegment->offset + length32; + + /* Now, we zoom to the end of the text, so we can pick up */ + /* afterward. */ + if (!NITF_IO_SUCCESS(nitf_IOInterface_seek(reader->input, + textSegment->end, + NITF_SEEK_SET, error))) + { + goto CATCH_ERROR; + } + } + + NITF_TRY_GET_UINT32(reader->record->header->numDataExtensions, + &num32, error); + + for (i = 0; i < num32; i++) + { + /* Construct a new segment */ + nitf_DESegment *deSegment = nitf_DESegment_construct(error); + if (!deSegment) + goto CATCH_ERROR; + + /* Push it onto the back of the list of segments */ + if (!nitf_List_pushBack(reader->record->dataExtensions, + (NITF_DATA *) deSegment, error)) + { + nitf_DESegment_destruct(&deSegment); + goto CATCH_ERROR; + } + + if (!readDESubheader(reader, i, fver, error)) + goto CATCH_ERROR; + + /* readDESubheader takes care of zooming/reading the DES Data */ + /* if it is a TRE_OVERFLOW, it reads it, so we can't always skip it */ + } + + NITF_TRY_GET_UINT32(reader->record->header->numReservedExtensions, + &num32, error); + for (i = 0; i < num32; i++) + { + /* Construct a new segment */ + nitf_RESegment *reSegment = nitf_RESegment_construct(error); + if (!reSegment) + goto CATCH_ERROR; + + /* Push it onto the back of the list of segments */ + if (!nitf_List_pushBack(reader->record->reservedExtensions, + (NITF_DATA *) reSegment, error)) + { + nitf_RESegment_destruct(&reSegment); + goto CATCH_ERROR; + } + + if (!readRESubheader(reader, i, fver, error)) + goto CATCH_ERROR; + + /* Now, we zoom to the end of the RES, so we can pick up */ + /* afterward. */ + if (!NITF_IO_SUCCESS(nitf_IOInterface_seek(reader->input, + reSegment->end, + NITF_SEEK_SET, + error))) + { + goto CATCH_ERROR; + } + } + + return reader->record; + +CATCH_ERROR: + nitf_Record_destruct(&reader->record); + resetIOInterface(reader); + return NULL; +} + + +NITFPRIV(nitf_DecompressionInterface *) getDecompIface(const char *comp, + int *bad, + nitf_Error * error) +{ + nitf_PluginRegistry *reg; + nitf_DecompressionInterface *decompIface; + NITF_PLUGIN_DECOMPRESSION_CONSTRUCT_FUNCTION constructDecompIface; + + /* Set bad to 0 (we are good so far) */ + *bad = 0; + + /* Find the decompression interface here */ + reg = nitf_PluginRegistry_getInstance(error); + if (!reg) + { + /* The plugin registry populated this error */ + *bad = 1; + return NULL; + } + /* Now retrieve the decomp iface creator */ + constructDecompIface = + nitf_PluginRegistry_retrieveDecompConstructor(reg, + comp, bad, error); + if (*bad) + { + /* The plugin registry encountered an error */ + return NULL; + } + + if (constructDecompIface == NULL) + { + /* We have no decompressor registered, so ignore */ + nitf_Debug_flogf(stderr, + "****Setting NULL interface for decompressor!******\n"); + return NULL; + } + decompIface = + (nitf_DecompressionInterface *) (*constructDecompIface) (comp, + error); + if (decompIface == NULL) + { + /* We had a bad encounter while creating the */ + /* decompression object. The error should be populated, */ + /* so go home... */ + *bad = 1; + } + return decompIface; +} + + +NITFPRIV(nitf_ImageIO *) allocIO(nitf_ImageSegment * segment, + nrt_HashTable * options, + nitf_Error * error) +{ + char compBuf[NITF_IC_SZ + 1]; /* holds the compression string */ + int bad = 0; + nitf_DecompressionInterface *decompIface = NULL; + /*nitf_CompressionInterface* compIface = NULL; */ + if (!segment) + { + nitf_Error_init(error, + "This operation requires a valid ImageSegment!", + NITF_CTXT, NITF_ERR_INVALID_OBJECT); + return NULL; + } + if (!segment->subheader) + { + nitf_Error_init(error, + "This operation requires a valid ImageSubheader!", + NITF_CTXT, NITF_ERR_INVALID_OBJECT); + return NULL; + } + + /* get the compression string */ + nitf_Field_get(segment->subheader->NITF_IC, + compBuf, NITF_CONV_STRING, NITF_IC_SZ + 1, error); + + if (memcmp(compBuf, "NC", 2) != 0 && + memcmp(compBuf, "NM", 2) != 0) + { + /* get the decompression interface */ + decompIface = getDecompIface(compBuf, &bad, error); + + if (bad) + { + /* The getDecompIface() function failed */ + return NULL; + } + } + /* compIface = getCompIface(segment->subheader->NITF_IC, + * bad, error); + */ + + /* Shouldnt we also have the compression ratio?? */ + return nitf_ImageIO_construct(segment->subheader, + segment->imageOffset, + segment->imageEnd - segment->imageOffset, + NULL, decompIface, options, error); +} + + +NITFAPI(nitf_ImageReader *) nitf_Reader_newImageReader( + nitf_Reader * reader, + int imageSegmentNumber, + nrt_HashTable * options, + nitf_Error * error) +{ + int i; + nitf_ListIterator iter; + nitf_ListIterator end; + nitf_ImageSegment *segment = NULL; + nitf_ImageReader *imageReader = + (nitf_ImageReader *) NITF_MALLOC(sizeof(nitf_ImageReader)); + if (!imageReader) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), NITF_CTXT, + NITF_ERR_MEMORY); + return NULL; + } + + iter = nitf_List_begin(reader->record->images); + end = nitf_List_end(reader->record->images); + + /* Important, this is starting at zero */ + for (i = 0; i <= imageSegmentNumber; i++) + { + segment = (nitf_ImageSegment *) nitf_ListIterator_get(&iter); + /* We have expired without finding the segment */ + /* they are talking about, so throw something at them */ + if (nitf_ListIterator_equals(&iter, &end)) + { + nitf_Error_initf(error, + NITF_CTXT, + NITF_ERR_INVALID_OBJECT, + "Index [%d] is not a valid image segment", + imageSegmentNumber); + nitf_ImageReader_destruct(&imageReader); + return NULL; + } + nitf_ListIterator_increment(&iter); + } + + imageReader->input = reader->input; + imageReader->imageDeblocker = allocIO(segment, options, error); + if (!imageReader->imageDeblocker) + { + nitf_ImageReader_destruct(&imageReader); + return NULL; + } + if (segment == NULL) + { + nitf_Error_initf(error, + NITF_CTXT, + NITF_ERR_INVALID_OBJECT, + "Index [%d] is not a valid image segment", + imageSegmentNumber); + nitf_ImageReader_destruct(&imageReader); + return NULL; + } + imageReader->directBlockRead = 0; + return imageReader; +} + + +NITFAPI(nitf_SegmentReader *) nitf_Reader_newTextReader +(nitf_Reader * reader, int textSegmentNumber, nitf_Error * error) +{ + nitf_SegmentReader *textReader; /* The result */ + nitf_ListIterator iter; /* Iterators to used find segment in list */ + nitf_ListIterator end; + nitf_TextSegment *text; /* Associated DE segment */ + int i; + + /* Find the associated segment */ + text = NULL; + iter = nitf_List_begin(reader->record->texts); + end = nitf_List_end(reader->record->texts); + for (i = 0; i <= textSegmentNumber; i++) + { + text = (nitf_TextSegment *) nitf_ListIterator_get(&iter); + if (nitf_ListIterator_equals(&iter, &end)) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_INVALID_OBJECT, + "Index [%d] is not a valid Text segment", + textSegmentNumber); + return NULL; + } + nitf_ListIterator_increment(&iter); + } + + /* Allocate the object */ + textReader = + (nitf_SegmentReader *) NITF_MALLOC(sizeof(nitf_SegmentReader)); + if (!textReader) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), NITF_CTXT, + NITF_ERR_MEMORY); + return NULL; + } + + /* set the fields */ + textReader->input = reader->input; + textReader->dataLength = text->end - text->offset; + textReader->baseOffset = text->offset; + textReader->virtualOffset = 0; + + return (textReader); +} + + +NITFAPI(nitf_SegmentReader *) nitf_Reader_newGraphicReader +(nitf_Reader * reader, int index, nitf_Error * error) +{ + nitf_SegmentReader *segmentReader; + nitf_ListIterator iter; + nitf_ListIterator end; + nitf_GraphicSegment *segment = NULL; + + /* Find the associated segment */ + iter = nitf_List_at(reader->record->graphics, index); + end = nitf_List_end(reader->record->graphics); + if (nitf_ListIterator_equals(&iter, &end)) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_INVALID_OBJECT, + "Index [%d] is not a valid Graphic segment", + index); + return NULL; + } + segment = (nitf_GraphicSegment *) nitf_ListIterator_get(&iter); + + /* Allocate the object */ + segmentReader = + (nitf_SegmentReader *) NITF_MALLOC(sizeof(nitf_SegmentReader)); + if (!segmentReader) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), NITF_CTXT, + NITF_ERR_MEMORY); + return NULL; + } + + /* set the fields */ + segmentReader->input = reader->input; + segmentReader->dataLength = segment->end - segment->offset; + segmentReader->baseOffset = segment->offset; + segmentReader->virtualOffset = 0; + + return segmentReader; +} + + +NITFAPI(nitf_SegmentReader *) nitf_Reader_newDEReader(nitf_Reader *reader, + int index, + nitf_Error * error) +{ + nitf_SegmentReader *segmentReader; + nitf_ListIterator iter; + nitf_ListIterator end; + nitf_DESegment *segment = NULL; + + /* Find the associated segment */ + iter = nitf_List_at(reader->record->dataExtensions, index); + end = nitf_List_end(reader->record->dataExtensions); + if (nitf_ListIterator_equals(&iter, &end)) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_INVALID_OBJECT, + "Index [%d] is not a valid Graphic segment", + index); + return NULL; + } + segment = (nitf_DESegment *) nitf_ListIterator_get(&iter); + + /* Allocate the object */ + segmentReader = + (nitf_SegmentReader *) NITF_MALLOC(sizeof(nitf_SegmentReader)); + if (!segmentReader) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), NITF_CTXT, + NITF_ERR_MEMORY); + return NULL; + } + + /* set the fields */ + segmentReader->input = reader->input; + segmentReader->dataLength = segment->end - segment->offset; + segmentReader->baseOffset = segment->offset; + segmentReader->virtualOffset = 0; + + return segmentReader; + +} + + +NITFAPI(nitf_Version) nitf_Reader_getNITFVersion(const char* fileName) +{ + nitf_IOHandle handle; + nitf_Error error; + char fhdr[NITF_FHDR_SZ]; + char fver[NITF_FVER_SZ]; + nitf_Version version = NITF_VER_UNKNOWN; + + handle = nitf_IOHandle_create(fileName, NITF_ACCESS_READONLY, + NITF_OPEN_EXISTING, &error); + if (NITF_INVALID_HANDLE(handle)) + goto CLEAN_AND_RETURN; + + if (!nitf_IOHandle_read(handle, fhdr, NITF_FHDR_SZ, &error)) + goto CLEAN_AND_RETURN; + if (!nitf_IOHandle_read(handle, fver, NITF_FVER_SZ, &error)) + goto CLEAN_AND_RETURN; + + /* NSIF1.0 == NITF2.1 */ + if ((strncmp(fhdr, "NITF", NITF_FHDR_SZ) == 0 && + strncmp(fver, "02.10", NITF_FVER_SZ) == 0) || + (strncmp(fhdr, "NSIF", NITF_FHDR_SZ) == 0 && + strncmp(fver, "01.00", NITF_FVER_SZ) == 0)) + { + version = NITF_VER_21; + } + else if (strncmp(fhdr, "NITF", NITF_FHDR_SZ) == 0 && + strncmp(fver, "02.00", NITF_FVER_SZ) == 0) + { + version = NITF_VER_20; + } + +CLEAN_AND_RETURN: + if (!NITF_INVALID_HANDLE(handle)) nitf_IOHandle_close(handle); + return version; +} diff --git a/modules/c/nitf/source/Record.c b/modules/c/nitf/source/Record.c new file mode 100644 index 000000000..8c49f6eb8 --- /dev/null +++ b/modules/c/nitf/source/Record.c @@ -0,0 +1,2324 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/Record.h" + +/* + * Destroy a list items that we have in our record. + * The first argument is the list pointer. + * The second argument is the type of object in the list + * For example, here is how to destroy the images segments: + * + * _NITF_TRASH_LIST(r->images, nitf_ImageSegment) + * + * Lp = r->images + * Ty = nitf_ImageSegment + * so... + * while (!nitf_List_isEmpty(r->images)) + * { + * nitf_ImageSegment* type = + * (nitf_ImageSegment*)nitf_List_popFront(r->images); + * + * nitf_ImageSegment_destruct(& type ); + * } + * + * Note that we dont want a semicolon at the end + */ +#define _NITF_TRASH_LIST(Lp_, Ty) \ + while (!nitf_List_isEmpty(Lp_)) \ + { \ + Ty* type = (Ty*)nitf_List_popFront(Lp_); \ + Ty##_destruct(& type ); \ + } + +/* Local functions and constants for overflow segments */ + +#define TRE_OVERFLOW_STR "TRE_OVERFLOW" +#define TRE_OVERFLOW_VERSION 1 + +NITFAPI(nitf_Uint32) nitf_Record_getNumReservedExtensions(nitf_Record* record, + nitf_Error* error) +{ + nitf_FileHeader* fhdr = record->header; + nitf_Uint32 num; + + /* This can only really happen if they have junk in NUMI */ + if (!nitf_Field_get(fhdr->NITF_NUMRES, &num, + NITF_CONV_UINT, sizeof(nitf_Uint32), error)) + return (nitf_Uint32) -1; + + return num; +} + +NITFAPI(nitf_Uint32) nitf_Record_getNumDataExtensions(nitf_Record* record, + nitf_Error* error) +{ + nitf_FileHeader* fhdr = record->header; + nitf_Uint32 num; + + /* This can only really happen if they have junk in the field */ + if (!nitf_Field_get(fhdr->NITF_NUMDES, &num, + NITF_CONV_UINT, sizeof(nitf_Uint32), error)) + return (nitf_Uint32) -1; + + return num; +} + +NITFAPI(nitf_Uint32) nitf_Record_getNumGraphics(nitf_Record* record, + nitf_Error* error) +{ + nitf_FileHeader* fhdr = record->header; + nitf_Uint32 num; + + /* This can only really happen if they have junk in the field */ + if (!nitf_Field_get(fhdr->NITF_NUMS, &num, + NITF_CONV_UINT, sizeof(nitf_Uint32), error)) + return (nitf_Uint32) -1; + + return num; +} + + +NITFAPI(nitf_Uint32) nitf_Record_getNumTexts(nitf_Record* record, + nitf_Error* error) +{ + nitf_FileHeader* fhdr = record->header; + nitf_Uint32 num; + + /* This can only really happen if they have junk in the field */ + if (!nitf_Field_get(fhdr->NITF_NUMT, &num, + NITF_CONV_UINT, sizeof(nitf_Uint32), error)) + return (nitf_Uint32) -1; + + return num; +} + + +NITFAPI(nitf_Uint32) nitf_Record_getNumLabels(nitf_Record* record, + nitf_Error* error) +{ + nitf_FileHeader* fhdr = record->header; + nitf_Uint32 num; + + /* This can only really happen if they have junk in the field */ + if (!nitf_Field_get(fhdr->NITF_NUMX, &num, + NITF_CONV_UINT, sizeof(nitf_Uint32), error)) + return (nitf_Uint32) -1; + + return num; +} + + +NITFAPI(nitf_Uint32) nitf_Record_getNumImages(nitf_Record* record, + nitf_Error* error) +{ + nitf_FileHeader* fhdr = record->header; + nitf_Uint32 num; + + /* This can only really happen if they have junk in the field */ + if (!nitf_Field_get(fhdr->NITF_NUMI, &num, + NITF_CONV_UINT, sizeof(nitf_Uint32), error)) + return (nitf_Uint32) -1; + return num; +} + + +/* + * addOverflowSegment adds a (DE) overflow section + * + * The security section in the new sections's header is initialized from the + * supplied file security object which should come from the assoicated segment + * + * All fields are set except DESSHL and DESDATA + * + * The index one based of the new segment is returned, or zero on error + * + * \param record Record to modify + * \param segmentIndex Index of associated segment + * \param segmentType security information from associated segment + * \param seecurityClass the classification value + * \param fileSecurity The file security record + * \param overflow A new DES segment + * \param error The error that occured if index is zero + */ + +NITFPRIV(nitf_Uint32) addOverflowSegment(nitf_Record *record, + nitf_Uint32 segmentIndex, + char *segmentType, + nitf_Field *securityClass, + nitf_FileSecurity *fileSecurity, + nitf_DESegment **overflow, + nitf_Error *error) +{ + nitf_Uint32 overflowIndex; + + /* Create the segment */ + + overflowIndex = nitf_List_size(record->dataExtensions) + 1; + *overflow = nitf_Record_newDataExtensionSegment(record,error); + if(*overflow == NULL) + { + nitf_Error_init(error, + "Could not add overflow segment index", + NITF_CTXT, NITF_ERR_INVALID_OBJECT); + return 0; + } + + /* Set fields */ + nitf_FileSecurity_destruct(&((*overflow)->subheader->securityGroup)); + (*overflow)->subheader->securityGroup = + nitf_FileSecurity_clone(fileSecurity,error); + + nitf_Field_destruct(&((*overflow)->subheader->securityClass)); + (*overflow)->subheader->securityClass = + nitf_Field_clone(securityClass,error); + if ((*overflow)->subheader->securityClass == NULL) + return 0; + + + if (!nitf_Field_setString((*overflow)->subheader->NITF_DESTAG, + TRE_OVERFLOW_STR,error)) + return 0; + + if (!nitf_Field_setUint32((*overflow)->subheader->NITF_DESVER, + TRE_OVERFLOW_VERSION,error)) + return 0; + + if (!nitf_Field_setString((*overflow)->subheader->NITF_DESOFLW, + segmentType,error)) + return 0; + + if (!nitf_Field_setUint32((*overflow)->subheader->NITF_DESITEM, + segmentIndex,error)) + return 0; + + return overflowIndex; +} + +/* + * moveTREs - Move TREs from one section to another + * + * If the skip length is greater than zero, then initial TREs are skpped + * until the first TRE that makes the total skipped larger than the skip + * length. This is for transferring from the main segment to the DE segment + * (unmerge), the zero case is for DE to main segment (merge) + * + * The return is TRUE on success and FALSE on failure + * + * \param destination Source extension + * \param skipLength Amount of TRE data to skip + * \param error For errors + */ +NITFPRIV(NITF_BOOL) moveTREs(nitf_Extensions *source, + nitf_Extensions *destination, + nitf_Uint32 skipLength, + nitf_Error *error) +{ + nitf_ExtensionsIterator srcIter; /* Source extension iterator */ + nitf_ExtensionsIterator srcEnd; /* Source extension iterator end */ + nitf_TRE *tre; /* Current TRE */ + + srcIter = nitf_Extensions_begin(source); + srcEnd = nitf_Extensions_end(source); + + if(skipLength != 0) + { + nitf_Int32 skipLeft; /* Amount left to skip */ + nitf_Uint32 treLength; /* Length of current TRE */ + + skipLeft = skipLength; + while(nitf_ExtensionsIterator_notEqualTo(&srcIter, &srcEnd)) + { + tre = nitf_ExtensionsIterator_get(&srcIter); + treLength = (nitf_Uint32)tre->handler->getCurrentSize(tre, error); + skipLeft -= treLength; + if(skipLeft < 1) + break; + nitf_ExtensionsIterator_increment(&srcIter); + } + if(skipLeft > 1) /* No transfer required */ + srcIter = nitf_Extensions_end(source); + } + + srcEnd = nitf_Extensions_end(source); + + while(nitf_ExtensionsIterator_notEqualTo(&srcIter, &srcEnd)) + { + tre = nitf_Extensions_remove(source,&srcIter,error); + nitf_Extensions_appendTRE(destination,tre,error); + } + + return NITF_SUCCESS; +} + +/* + * fixOverflowIndexes reviews and corrects the indexes of DE overflow + * segments when any segment that might overflow (i.e., image segment) is + * removed. Removing a segment could effect the indexes in existing overflowed + * segments. + * + * If the segment being deleted does not have an overflow segment. If it has + * one, it shold be deleted before this function is called + * + * This function also removes the associated DE segent if it still exists + * + * Note: Adding a segment does not effect any existing overflows because new + * segments are added at the end of the corresponding segment list + * + * \param record Record + * \param type The type of DES + * \param segmentIndex Segment index (zero based) + * \param error Error + * + */ +NITFPRIV(NITF_BOOL) fixOverflowIndexes(nitf_Record *record, + char *type, + nitf_Uint32 segmentIndex, + nitf_Error *error) +{ + nitf_ListIterator deIter; /* For DE iterating */ + nitf_ListIterator deEnd; /* End point */ + nitf_DESubheader *subheader; /* Current DE segment subheader */ + char oflw[NITF_DESOFLW_SZ+1]; /* Parent segment type (DESOFLW) */ + nitf_Uint32 item; /* Segment index (DESITEM) */ + + /* + * Scan extensions for ones that have the same type + * and a index greater than + * the index of the segment being deleted. If this is + * the case decrement the + * overflow's index + */ + + deIter = nitf_List_begin(record->dataExtensions); + deEnd = nitf_List_begin(record->dataExtensions); + while(nitf_ListIterator_notEqualTo(&deIter, &deEnd)) + { + subheader = (nitf_DESubheader *) + ((nitf_DESegment *) nitf_ListIterator_get(&deIter))->subheader; + + if(!nitf_Field_get(subheader->NITF_DESOFLW,(NITF_DATA *) oflw, + NITF_CONV_STRING,NITF_DESOFLW_SZ+1,error)) + { + nitf_Error_init(error, + "Could not retrieve DESOVFLW field", + NITF_CTXT,NITF_ERR_INVALID_OBJECT); + return NITF_FAILURE; + } + + if(!nitf_Field_get(subheader->NITF_DESITEM,(NITF_DATA *) &item, + NITF_CONV_UINT,sizeof(item), error)) + { + nitf_Error_init(error, + "Could not retrieve DESITEM field", + NITF_CTXT,NITF_ERR_INVALID_OBJECT); + return NITF_FAILURE; + } + + if((strcmp(oflw, type) == 0) && (item > (segmentIndex + 1))) + if(!nitf_Field_setUint32(subheader->NITF_DESITEM,item-1,error)) + return 0; + + nitf_ListIterator_increment(&deIter); + } + + return NITF_SUCCESS; +} + +/* + * fixSegmentIndexes reviews and corrects the indexes of all overflowing + * segments (i.e., image segment) when any DE segment is removed. Removing a + * DE segment could effect the indexes of any existing overflowed segments. + * This function is called when any DE segment is remove, not just overflow + * segments. The file header is also checked. + * + * Note: Adding a DE segment does not effect any existing overflows because new + * segments are added at the end of the corresponding segment list + * + * \param record Record to fix + * \param index DE segment of removed segment zero based + * \param error for Error returns + * + */ + +NITFPRIV(NITF_BOOL) fixSegmentIndexes(nitf_Record *record, + nitf_Uint32 segmentIndex, + nitf_Error *error) +{ + nitf_FileHeader *header; /* File header */ + nitf_ListIterator segIter; /* Current segment list */ + nitf_ListIterator segEnd; /* Current segment list end */ + nitf_Uint32 deIndex; /* Desegment index */ + + /* File header */ + + header = record->header; + if(!nitf_Field_get(header->NITF_UDHOFL,(NITF_DATA *) &deIndex, + NITF_CONV_UINT,sizeof(deIndex), error)) + return NITF_FAILURE; + + if(deIndex > (segmentIndex + 1)) + if(!nitf_Field_setUint32(header->NITF_UDHOFL,deIndex-1,error)) + return NITF_FAILURE; + + if(!nitf_Field_get(header->NITF_XHDLOFL,(NITF_DATA *) &deIndex, + NITF_CONV_UINT,sizeof(deIndex), error)) + return NITF_FAILURE; + + if(deIndex > (segmentIndex + 1)) + if(!nitf_Field_setUint32(header->NITF_XHDLOFL,deIndex-1,error)) + return NITF_FAILURE; + + /* Image segments */ + + segIter = nitf_List_begin(record->images); + segEnd = nitf_List_end(record->images); + while(nitf_ListIterator_notEqualTo(&segIter, &segEnd)) + { + nitf_ImageSubheader *subheader; /* Current subheader */ + + subheader = (nitf_ImageSubheader *) + ((nitf_ImageSegment *) nitf_ListIterator_get(&segIter))->subheader; + + if(!nitf_Field_get(subheader->NITF_UDOFL,(NITF_DATA *) &deIndex, + NITF_CONV_UINT,sizeof(deIndex), error)) + return NITF_FAILURE; + + if(deIndex > (segmentIndex + 1)) + if(!nitf_Field_setUint32(subheader->NITF_UDOFL,deIndex-1,error)) + return NITF_FAILURE; + + if(!nitf_Field_get(subheader->NITF_IXSOFL,(NITF_DATA *) &deIndex, + NITF_CONV_UINT,sizeof(deIndex), error)) + return NITF_FAILURE; + + if(deIndex > (segmentIndex + 1)) + if(!nitf_Field_setUint32(subheader->NITF_IXSOFL,deIndex-1,error)) + return NITF_FAILURE; + + nitf_ListIterator_increment(&segIter); + } + + /* Graphics segments */ + + segIter = nitf_List_begin(record->images); + segEnd = nitf_List_end(record->images); + while(nitf_ListIterator_notEqualTo(&segIter, &segEnd)) + { + nitf_GraphicSubheader *subheader; /* Current subheader */ + + subheader = (nitf_GraphicSubheader *) + ((nitf_GraphicSegment *) nitf_ListIterator_get(&segIter))->subheader; + + if(!nitf_Field_get(subheader->NITF_SXSOFL,(NITF_DATA *) &deIndex, + NITF_CONV_UINT,sizeof(deIndex), error)) + return NITF_FAILURE; + + if(deIndex > (segmentIndex + 1)) + if(!nitf_Field_setUint32(subheader->NITF_SXSOFL,deIndex-1,error)) + return NITF_FAILURE; + + nitf_ListIterator_increment(&segIter); + } + + /* Label segments */ + + segIter = nitf_List_begin(record->labels); + segEnd = nitf_List_end(record->labels); + while(nitf_ListIterator_notEqualTo(&segIter, &segEnd)) + { + nitf_LabelSubheader *subheader; /* Current subheader */ + + subheader = (nitf_LabelSubheader *) + ((nitf_LabelSegment *) nitf_ListIterator_get(&segIter))->subheader; + + if(!nitf_Field_get(subheader->NITF_LXSOFL,(NITF_DATA *) &deIndex, + NITF_CONV_UINT,sizeof(deIndex), error)) + return NITF_FAILURE; + + if(deIndex > (segmentIndex + 1)) + if(!nitf_Field_setUint32(subheader->NITF_LXSOFL,deIndex-1,error)) + return NITF_FAILURE; + + nitf_ListIterator_increment(&segIter); + } + + /* Text segments */ + + segIter = nitf_List_begin(record->images); + segEnd = nitf_List_end(record->images); + while(nitf_ListIterator_notEqualTo(&segIter, &segEnd)) + { + nitf_TextSubheader *subheader; /* Current subheader */ + + subheader = (nitf_TextSubheader *) + ((nitf_GraphicSegment *) nitf_ListIterator_get(&segIter))->subheader; + + if(!nitf_Field_get(subheader->NITF_TXSOFL,(NITF_DATA *) &deIndex, + NITF_CONV_UINT,sizeof(deIndex), error)) + return NITF_FAILURE; + + if(deIndex > (segmentIndex + 1)) + if(!nitf_Field_setUint32(subheader->NITF_TXSOFL,deIndex-1,error)) + return NITF_FAILURE; + nitf_ListIterator_increment(&segIter); + } + + return NITF_SUCCESS; +} + +/* + * This macro assumes existance of some kind of NITF header/subheader named + * 'header,' an error named 'error', and a catch clause called 'CATCH_ERROR' + * within the caller + */ +#define _NITF_SET_FIELD(fld, val) if (!nitf_Field_setRawData(header->fld, (NITF_DATA*)val, fld##_SZ, error)) goto CATCH_ERROR + +NITFPRIV(nitf_FileHeader*) createDefaultFileHeader(nitf_Version version, + nitf_Error* error) +{ + + nitf_FileHeader* header = nitf_FileHeader_construct(error); + + /* Got nothing */ + if (!header) return NULL; + + _NITF_SET_FIELD(NITF_FHDR, "NITF"); + + /* NOW, set any version-specific data */ + if (version == NITF_VER_20) + { + _NITF_SET_FIELD(NITF_FVER, "02.00"); + /* Resize for NITF 2.0 */ + if (!nitf_FileSecurity_resizeForVersion(header->securityGroup, + version, error)) + goto CATCH_ERROR; + } + + /* The default is 2.1 */ + else + { + _NITF_SET_FIELD(NITF_FVER, "02.10"); + } + + _NITF_SET_FIELD(NITF_STYPE, "BF01"); + + /* Set 'U' by default. This makes life easier for lots of folks */ + _NITF_SET_FIELD(NITF_FSCLAS, "U"); + + /* I can almost guarantee its not encrypted */ + _NITF_SET_FIELD(NITF_ENCRYP, "0"); + + return header; + +CATCH_ERROR: + nitf_FileHeader_destruct(&header); + return NULL; +} + +NITFPRIV(nitf_ImageSegment*) createDefaultImageSegment(nitf_Version version, + nitf_Uint32 displayLevel, + nitf_Error * error) +{ + + /* Create the new segment */ + nitf_ImageSegment* segment = nitf_ImageSegment_construct(error); + nitf_ImageSubheader* header = segment->subheader; + + /* Update the version of the FileSecurity, if necessary */ + + if (version == NITF_VER_20) + { + /* Resize */ + nitf_FileSecurity_resizeForVersion(header->securityGroup, + version, + error); + } + + _NITF_SET_FIELD(NITF_IM, "IM"); + _NITF_SET_FIELD(NITF_ENCRYP, "0"); + /* This *could* be 'L', but its unlikely */ + _NITF_SET_FIELD(NITF_PJUST, "R"); + /* This is often set to 1.0 */ + _NITF_SET_FIELD(NITF_IMAG, "1.0 "); + /* IC should default to NC -- we dont know we have a mask yet */ + _NITF_SET_FIELD(NITF_IC, "NC"); + + _NITF_SET_FIELD(NITF_ISCLAS, "U"); + + if (!nitf_Field_setUint32(header->NITF_IDLVL, displayLevel, error)) + goto CATCH_ERROR; + + return segment; + +CATCH_ERROR: + return NITF_FAILURE; +} + +NITFAPI(nitf_Record *) nitf_Record_construct(nitf_Version version, + nitf_Error * error) +{ + nitf_Record *record = (nitf_Record *) NITF_MALLOC(sizeof(nitf_Record)); + if (!record) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + return NULL; + } + + /* Right now, we are only doing these */ + record->header = NULL; + record->images = NULL; + + /* Right now, we aren't doing these things */ + record->graphics = NULL; + record->labels = NULL; + record->texts = NULL; + record->dataExtensions = NULL; + record->reservedExtensions = NULL; + + /* + * This block does the children creations + * In the event of a constructor error, the + * error object is already populated, and + * since we have all of our objects NULL-inited + * we have the same behavior for each failure. + * It lives at the end and is called TRAGIC + */ + record->header = createDefaultFileHeader(version, error); + if (!record->header) + goto CATCH_TRAGIC; + + record->images = nitf_List_construct(error); + if (!record->images) + goto CATCH_TRAGIC; + + record->graphics = nitf_List_construct(error); + if (!record->graphics) + goto CATCH_TRAGIC; + + record->labels = nitf_List_construct(error); + if (!record->labels) + goto CATCH_TRAGIC; + + record->texts = nitf_List_construct(error); + if (!record->texts) + goto CATCH_TRAGIC; + + record->dataExtensions = nitf_List_construct(error); + if (!record->dataExtensions) + goto CATCH_TRAGIC; + + record->reservedExtensions = nitf_List_construct(error); + if (!record->reservedExtensions) + goto CATCH_TRAGIC; + + + /* If all went well, we are very happy. Now return */ + return record; + +CATCH_TRAGIC: + /* + * If something went wrong, somebody threw to us + * So tragic! So young to die! + */ + nitf_Record_destruct(&record); + return NULL; +} + + +NITFAPI(nitf_Record *) nitf_Record_clone(nitf_Record * source, + nitf_Error * error) +{ + nitf_Record *record = NULL; + + if (!source) + { + nitf_Error_initf(error, + NITF_CTXT, + NITF_ERR_INVALID_OBJECT, + "Trying to clone NULL pointer"); + return NULL; + } + + record = (nitf_Record *) NITF_MALLOC(sizeof(nitf_Record)); + if (!record) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + return NULL; + } + + /* Null-set in case we auto-destruct */ + record->header = NULL; + record->images = NULL; + record->graphics = NULL; + record->labels = NULL; + record->texts = NULL; + record->dataExtensions = NULL; + record->reservedExtensions = NULL; + + /* Right now, we are only doing the header and image setup */ + record->header = nitf_FileHeader_clone(source->header, error); + if (!record->header) + { + /* Destruct gracefully if we had a problem */ + nitf_Record_destruct(&record); + return NULL; + } + record->images = + nitf_List_clone(source->images, + (NITF_DATA_ITEM_CLONE) nitf_ImageSegment_clone, + error); + + if (!record->images) + { + /* Destruct gracefully if we had a problem */ + nitf_Record_destruct(&record); + return NULL; + } + + record->graphics = + nitf_List_clone(source->graphics, + (NITF_DATA_ITEM_CLONE) nitf_GraphicSegment_clone, + error); + if (!record->graphics) + { + /* Destruct gracefully if we had a problem */ + nitf_Record_destruct(&record); + return NULL; + } + + record->labels = + nitf_List_clone(source->labels, + (NITF_DATA_ITEM_CLONE) nitf_LabelSegment_clone, + error); + if (!record->labels) + { + /* Destruct gracefully if we had a problem */ + nitf_Record_destruct(&record); + return NULL; + } + + record->texts = + nitf_List_clone(source->texts, + (NITF_DATA_ITEM_CLONE) nitf_TextSegment_clone, + error); + if (!record->texts) + { + /* Destruct gracefully if we had a problem */ + nitf_Record_destruct(&record); + return NULL; + } + + record->dataExtensions = + nitf_List_clone(source->dataExtensions, + (NITF_DATA_ITEM_CLONE) nitf_DESegment_clone, + error); + if (!record->dataExtensions) + { + /* Destruct gracefully if we had a problem */ + nitf_Record_destruct(&record); + return NULL; + } + + record->reservedExtensions = + nitf_List_clone(source->reservedExtensions, + (NITF_DATA_ITEM_CLONE) nitf_RESegment_clone, + error); + if (!record->reservedExtensions) + { + /* Destruct gracefully if we had a problem */ + nitf_Record_destruct(&record); + return NULL; + } + + return record; + +} + + +NITFAPI(void) nitf_Record_destruct(nitf_Record ** record) +{ + if (*record) + { + if ((*record)->header) + { + nitf_FileHeader_destruct(&(*record)->header); + } + + /* + * When destroying these, we always use the same macro + * The macro is walking the list and deleting the items + * by calling the segment destructors by name + */ + if ((*record)->images) + { + /* Walk the list and destroy it */ + _NITF_TRASH_LIST((*record)->images, + nitf_ImageSegment) + nitf_List_destruct(&(*record)->images); + } + + if ((*record)->graphics) + { + /* Walk the list and destroy it */ + _NITF_TRASH_LIST((*record)->graphics, + nitf_GraphicSegment) + nitf_List_destruct(&(*record)->graphics); + } + + if ((*record)->labels) + { + /* Walk the list and destroy it */ + _NITF_TRASH_LIST((*record)->labels, + nitf_LabelSegment) + nitf_List_destruct(&(*record)->labels); + } + + if ((*record)->texts) + { + /* Walk the list and destroy it */ + _NITF_TRASH_LIST((*record)->texts, + nitf_TextSegment) + nitf_List_destruct(&(*record)->texts); + } + + if ((*record)->dataExtensions) + { + /* Walk the list and destroy it */ + _NITF_TRASH_LIST((*record)->dataExtensions, + nitf_DESegment) + nitf_List_destruct(&(*record)->dataExtensions); + } + + if ((*record)->reservedExtensions) + { + /* Walk the list and destroy it */ + _NITF_TRASH_LIST((*record)->reservedExtensions, + nitf_RESegment) + nitf_List_destruct(&(*record)->reservedExtensions); + } + + NITF_FREE(*record); + *record = NULL; + } +} + + +NITFAPI(nitf_Version) nitf_Record_getVersion(nitf_Record * record) +{ + char version[6]; + nitf_Version fver = NITF_VER_UNKNOWN; + + /* Make sure the pieces of what we want exist */ + if (record && record->header && record->header->NITF_FVER) + { + memcpy(version, record->header->NITF_FVER->raw, 5); + version[5] = 0; + + /* NSIF1.0 == NITF2.1 (from our point of view anyway) */ + if (strncmp(record->header->NITF_FHDR->raw, "NSIF", 4) == 0 + || strncmp(version, "02.10", 5) == 0) + fver = NITF_VER_21; + else if (strncmp(version, "02.00", 5) == 0) + fver = NITF_VER_20; + } + return fver; +} + + +NITFAPI(nitf_ImageSegment *) nitf_Record_newImageSegment(nitf_Record* record, + nitf_Error *error) +{ + nitf_ImageSegment *segment = NULL; + nitf_ComponentInfo *info = NULL; + nitf_ComponentInfo **infoArray = NULL; + nitf_Uint32 num; + nitf_Uint32 i; + nitf_Version version; + + + /* Get current num of images */ + NITF_TRY_GET_UINT32(record->header->NITF_NUMI, &num, error); + + /* Verify the number is ok */ + if (num < 0) + num = 0; + else if (num >= 999) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_INVALID_OBJECT, + "Cannot add another image segment, already have %d", + num); + goto CATCH_ERROR; + } + + + /* Create the new info */ + info = nitf_ComponentInfo_construct(NITF_LISH_SZ, NITF_LI_SZ, error); + if (!info) + goto CATCH_ERROR; + + version = nitf_Record_getVersion(record); + segment = createDefaultImageSegment(version, num + 1, error); + if (!segment) + goto CATCH_ERROR; + + + /* Add to the list */ + if (!nitf_List_pushBack(record->images, (NITF_DATA *) segment, error)) + goto CATCH_ERROR; + + + /* Make new array, one bigger */ + infoArray = + (nitf_ComponentInfo **) NITF_MALLOC(sizeof(nitf_ComponentInfo *) * + (num + 1)); + if (!infoArray) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + goto CATCH_ERROR; + } + + /* Iterate over current infos */ + for (i = 0; i < num; ++i) + infoArray[i] = record->header->imageInfo[i]; + + /* Add the new one */ + infoArray[i] = info; + num++; + + if (!nitf_Field_setUint32(record->header->NITF_NUMI, num, error)) + goto CATCH_ERROR; + + /* Delete old one, if there, and set to new one */ + if (record->header->imageInfo) + NITF_FREE(record->header->imageInfo); + + record->header->imageInfo = infoArray; + + /* Return the segment */ + return segment; + +CATCH_ERROR: + if (info) + nitf_ComponentInfo_destruct(&info); + + if (infoArray) + NITF_FREE(infoArray); + + + + if (segment) + nitf_ImageSegment_destruct(&segment); + + return NULL; +} + + +NITFAPI(nitf_GraphicSegment *) +nitf_Record_newGraphicSegment(nitf_Record* record, + nitf_Error * error) +{ + nitf_GraphicSegment *segment = NULL; + nitf_GraphicSubheader *header = NULL; + nitf_ComponentInfo *info = NULL; + nitf_ComponentInfo **infoArray = NULL; + nitf_Uint32 num; + nitf_Uint32 i; + nitf_Version version; + + /* Get current num of graphics */ + NITF_TRY_GET_UINT32(record->header->NITF_NUMS, &num, error); + + /* Verify the number is ok */ + if (num < 0) + num = 0; + else if (num >= 999) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_INVALID_OBJECT, + "Cannot add another graphic segment, already have %d", num); + goto CATCH_ERROR; + } + + + /* Create the new info */ + info = nitf_ComponentInfo_construct(NITF_LSSH_SZ, NITF_LS_SZ, error); + if (!info) + goto CATCH_ERROR; + + /* Create the new segment */ + segment = nitf_GraphicSegment_construct(error); + if (!segment) + goto CATCH_ERROR; + + + header = segment->subheader; + + _NITF_SET_FIELD(NITF_SY, "SY"); + _NITF_SET_FIELD(NITF_ENCRYP, "0"); + _NITF_SET_FIELD(NITF_SSCLAS, "U"); + + if (!nitf_Field_setUint32(header->NITF_SDLVL, num + 1, error)) + goto CATCH_ERROR; + + /* Update the version of the FileSecurity, if necessary */ + version = nitf_Record_getVersion(record); + if (version == NITF_VER_20) + { + /* Resize */ + if (!nitf_FileSecurity_resizeForVersion(header->securityGroup, + version, error)) + goto CATCH_ERROR; + } + + /* Add to the list */ + if (!nitf_List_pushBack(record->graphics, (NITF_DATA *) segment, error)) + goto CATCH_ERROR; + + /* Make new array, one bigger */ + infoArray = + (nitf_ComponentInfo **) NITF_MALLOC(sizeof(nitf_ComponentInfo *) * + (num + 1)); + if (!infoArray) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + goto CATCH_ERROR; + } + + /* Iterate over current infos */ + for (i = 0; i < num; ++i) + infoArray[i] = record->header->graphicInfo[i]; + + /* Add the new one */ + infoArray[i] = info; + num++; + + /* Convert the data to chars */ + if (!nitf_Field_setUint32(record->header->NITF_NUMS, num, error)) + goto CATCH_ERROR; + + /* Delete old one, if there, and set to new one */ + if (record->header->graphicInfo) + NITF_FREE(record->header->graphicInfo); + + record->header->graphicInfo = infoArray; + + /* Return the segment */ + return segment; + +CATCH_ERROR: + + if (info) + nitf_ComponentInfo_destruct(&info); + + if (infoArray) + NITF_FREE(infoArray); + + + + if (segment) + nitf_GraphicSegment_destruct(&segment); + + return NULL; +} + + +NITFAPI(nitf_TextSegment *) nitf_Record_newTextSegment(nitf_Record* record, + nitf_Error* error) +{ + nitf_TextSegment *segment = NULL; + nitf_TextSubheader* header = NULL; + nitf_ComponentInfo *info = NULL; + nitf_ComponentInfo **infoArray = NULL; + nitf_Uint32 num; + nitf_Uint32 i; + nitf_Version version; + + + /* Get current num of texts */ + NITF_TRY_GET_UINT32(record->header->numTexts, &num, error); + + /* Verify the number is ok */ + if (num < 0) + num = 0; + else if (num >= 999) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_INVALID_OBJECT, + "Cannot add another text segment, already have %d", num); + goto CATCH_ERROR; + } + + /* Create the new info */ + info = nitf_ComponentInfo_construct(NITF_LTSH_SZ, NITF_LT_SZ, error); + if (!info) + { + goto CATCH_ERROR; + } + + /* Create the new segment */ + segment = nitf_TextSegment_construct(error); + if (!segment) + goto CATCH_ERROR; + + header = segment->subheader; + + _NITF_SET_FIELD(NITF_TE, "TE"); + _NITF_SET_FIELD(NITF_ENCRYP, "0"); + _NITF_SET_FIELD(NITF_SSCLAS, "U"); + + /* Update the version of the FileSecurity, if necessary */ + version = nitf_Record_getVersion(record); + if (version == NITF_VER_20) + { + /* Resize */ + nitf_FileSecurity_resizeForVersion(header->securityGroup, version, error); + } + + /* Add to the list */ + if (!nitf_List_pushBack(record->texts, (NITF_DATA *) segment, error)) + { + goto CATCH_ERROR; + } + + /* Make new array, one bigger */ + infoArray = + (nitf_ComponentInfo **) NITF_MALLOC(sizeof(nitf_ComponentInfo *) * + (num + 1)); + if (!infoArray) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + goto CATCH_ERROR; + } + + /* Iterate over current infos */ + for (i = 0; i < num; ++i) + { + infoArray[i] = record->header->textInfo[i]; + } + /* Add the new one */ + infoArray[i] = info; + num++; + + if (!nitf_Field_setUint32(record->header->NITF_NUMT, num, error)) + goto CATCH_ERROR; + + /* Delete old one, if there, and set to new one */ + if (record->header->textInfo) + NITF_FREE(record->header->textInfo); + + record->header->textInfo = infoArray; + + /* Return the segment */ + return segment; + +CATCH_ERROR: + + if (info) + nitf_ComponentInfo_destruct(&info); + + if (infoArray) + NITF_FREE(infoArray); + + + if (segment) + nitf_TextSegment_destruct(&segment); + + return NULL; +} + + +NITFAPI(nitf_DESegment *) +nitf_Record_newDataExtensionSegment(nitf_Record * record, + nitf_Error * error) +{ + nitf_DESegment *segment = NULL; + nitf_DESubheader* header = NULL; + nitf_ComponentInfo *info = NULL; + nitf_ComponentInfo **infoArray = NULL; + nitf_Uint32 num; + nitf_Uint32 i; + nitf_Version version; + + /* Get current num of DEs */ + NITF_TRY_GET_UINT32(record->header->NITF_NUMDES, &num, error); + + /* Verify the number is ok */ + if (num < 0) + num = 0; + + else if (num >= 999) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_INVALID_OBJECT, + "Cannot add another DE segment, already have %d", num); + goto CATCH_ERROR; + } + + /* Create the new info */ + info = nitf_ComponentInfo_construct(NITF_LDSH_SZ, NITF_LD_SZ, error); + if (!info) + goto CATCH_ERROR; + + /* Create the new segment */ + segment = nitf_DESegment_construct(error); + if (!segment) + goto CATCH_ERROR; + + header = segment->subheader; + + _NITF_SET_FIELD(NITF_DE, "DE"); + _NITF_SET_FIELD(NITF_DESCLAS, "U"); + + /* Update the version of the FileSecurity, if necessary */ + version = nitf_Record_getVersion(record); + if (version == NITF_VER_20) + { + /* Resize */ + if (!nitf_FileSecurity_resizeForVersion(header->securityGroup, + version, error)) + goto CATCH_ERROR; + } + + /* Add to the list */ + if (!nitf_List_pushBack(record->dataExtensions,(NITF_DATA *)segment, error)) + goto CATCH_ERROR; + + + /* Make new array, one bigger */ + infoArray = + (nitf_ComponentInfo **) NITF_MALLOC(sizeof(nitf_ComponentInfo *) * + (num + 1)); + if (!infoArray) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + goto CATCH_ERROR; + } + + /* Iterate over current infos */ + for (i = 0; i < num; ++i) + { + infoArray[i] = record->header->dataExtensionInfo[i]; + } + /* Add the new one */ + infoArray[i] = info; + num++; + + /* Convert the data to chars */ + if (!nitf_Field_setUint32(record->header->NITF_NUMDES, num, error)) + goto CATCH_ERROR; + + /* Delete old one, if there, and set to new one */ + if (record->header->dataExtensionInfo) + { + NITF_FREE(record->header->dataExtensionInfo); + } + record->header->dataExtensionInfo = infoArray; + + /* Return the segment */ + return segment; + +CATCH_ERROR: + + if (info) + nitf_ComponentInfo_destruct(&info); + + if (infoArray) + NITF_FREE(infoArray); + + if (segment) + nitf_DESegment_destruct(&segment); + + return NULL; +} + + +NITFAPI(NITF_BOOL) nitf_Record_removeImageSegment(nitf_Record * record, + nitf_Uint32 segmentNumber, + nitf_Error * error) +{ + nitf_Uint32 num; + nitf_ComponentInfo **infoArray = NULL; + nitf_ImageSegment* segment = NULL; + nitf_Uint32 i; + nitf_ListIterator iter = nitf_List_at(record->images, segmentNumber); + + if (iter.current == NULL) + { + nitf_Error_initf(error, + NITF_CTXT, + NITF_ERR_INVALID_OBJECT, + "Invalid image segment number"); + goto CATCH_ERROR; + } + + /* Remove from the list */ + segment = (nitf_ImageSegment*)nitf_List_remove(record->images, &iter); + /* Destroy it */ + nitf_ImageSegment_destruct(&segment); + + /* Get current num*/ + NITF_TRY_GET_UINT32(record->header->numImages, &num, error); + + /* If we actually need to resize */ + if (num > 1) + { + /* Make new array, one smaller */ + infoArray = + (nitf_ComponentInfo **) NITF_MALLOC(sizeof(nitf_ComponentInfo *) * + (num - 1)); + + /* Iterate over current infos */ + for (i = 0; i < segmentNumber; ++i) + { + infoArray[i] = record->header->imageInfo[i]; + } + for (i = segmentNumber + 1; i < num; ++i) + { + infoArray[i - 1] = record->header->imageInfo[i]; + } + } + + /* Update the num field in the header */ + num--; + + if (!nitf_Field_setUint32(record->header->NITF_NUMI, num, error)) + goto CATCH_ERROR; + + /* Delete old one, if there, and set to new one */ + if (record->header->imageInfo) + NITF_FREE(record->header->imageInfo); + + record->header->imageInfo = infoArray; + + /* Update the indexes in any overflow segments */ + if(!fixOverflowIndexes(record, "UDID", segmentNumber, error)) + return NITF_FAILURE; + + if(!fixOverflowIndexes(record, "IXSHD", segmentNumber, error)) + return NITF_FAILURE; + + return NITF_SUCCESS; + +CATCH_ERROR: + if (infoArray) + NITF_FREE(infoArray); + + + return NITF_FAILURE; +} + + +NITFAPI(NITF_BOOL) nitf_Record_removeGraphicSegment(nitf_Record * record, + nitf_Uint32 segmentNumber, + nitf_Error * error) +{ + nitf_Uint32 num; + nitf_ComponentInfo **infoArray = NULL; + nitf_GraphicSegment* segment = NULL; + nitf_Uint32 i; + nitf_ListIterator iter = nitf_List_at(record->graphics, segmentNumber); + + if (iter.current == NULL) + { + nitf_Error_initf(error, + NITF_CTXT, + NITF_ERR_INVALID_OBJECT, + "Invalid graphic segment number"); + goto CATCH_ERROR; + } + + /* Remove from the list */ + segment = (nitf_GraphicSegment*)nitf_List_remove(record->graphics, &iter); + /* Destroy it */ + nitf_GraphicSegment_destruct(&segment); + + /* Get current num */ + NITF_TRY_GET_UINT32(record->header->numGraphics, &num, error); + + /* If we actually need to resize */ + if (num > 1) + { + /* Make new array, one smaller */ + infoArray = + (nitf_ComponentInfo **) NITF_MALLOC(sizeof(nitf_ComponentInfo *) * + (num - 1)); + + /* Iterate over current infos */ + for (i = 0; i < segmentNumber; ++i) + { + infoArray[i] = record->header->graphicInfo[i]; + } + for (i = segmentNumber + 1; i < num; ++i) + { + infoArray[i - 1] = record->header->graphicInfo[i]; + } + } + + /* Update the num field in the header */ + num--; + + if (!nitf_Field_setUint32(record->header->NITF_NUMS, num, error)) + goto CATCH_ERROR; + + + /* Delete old one, if there, and set to new one */ + if (record->header->graphicInfo) + NITF_FREE(record->header->graphicInfo); + + record->header->graphicInfo = infoArray; + + /* Update the indexes in any overflow segments */ + if(!fixOverflowIndexes(record, "SXSHD", segmentNumber, error)) + return NITF_FAILURE; + + return NITF_SUCCESS; + +CATCH_ERROR: + if (infoArray) + NITF_FREE(infoArray); + + + return NITF_FAILURE; +} + + +NITFAPI(NITF_BOOL) nitf_Record_removeLabelSegment(nitf_Record * record, + nitf_Uint32 segmentNumber, + nitf_Error * error) +{ + nitf_Uint32 num; + nitf_ComponentInfo **infoArray = NULL; + nitf_LabelSegment* segment = NULL; + nitf_Uint32 i; + + nitf_ListIterator iter = nitf_List_at(record->labels, segmentNumber); + + if (iter.current == NULL) + { + nitf_Error_initf(error, + NITF_CTXT, + NITF_ERR_INVALID_OBJECT, + "Invalid label segment number"); + goto CATCH_ERROR; + } + + /* Remove from the list */ + segment = (nitf_LabelSegment*)nitf_List_remove(record->labels, &iter); + + /* Destroy it */ + nitf_LabelSegment_destruct(&segment); + + /* Get current num */ + NITF_TRY_GET_UINT32(record->header->numLabels, &num, error); + + /* If we actually need to resize */ + if (num > 1) + { + /* Make new array, one smaller */ + infoArray = + (nitf_ComponentInfo **) NITF_MALLOC(sizeof(nitf_ComponentInfo *) * + (num - 1)); + + /* Iterate over current infos */ + for (i = 0; i < segmentNumber; ++i) + { + infoArray[i] = record->header->labelInfo[i]; + } + for (i = segmentNumber + 1; i < num; ++i) + { + infoArray[i - 1] = record->header->labelInfo[i]; + } + } + + /* Update the num field in the header */ + num--; + + if (!nitf_Field_setUint32(record->header->NITF_NUMX, num, error)) + goto CATCH_ERROR; + + /* Delete old one, if there, and set to new one */ + if (record->header->labelInfo) + NITF_FREE(record->header->labelInfo); + + record->header->labelInfo = infoArray; + + /* Update the indexes in any overflow segments */ + if(!fixOverflowIndexes(record, "LXSHD", segmentNumber, error)) + return NITF_FAILURE; + + return NITF_SUCCESS; + +CATCH_ERROR: + if (infoArray) + NITF_FREE(infoArray); + + + return NITF_FAILURE; +} + + +NITFAPI(NITF_BOOL) nitf_Record_removeTextSegment(nitf_Record * record, + nitf_Uint32 segmentNumber, + nitf_Error * error) +{ + nitf_Uint32 num; + nitf_ComponentInfo **infoArray = NULL; + nitf_TextSegment* segment = NULL; + nitf_Uint32 i; + nitf_ListIterator iter = nitf_List_at(record->texts, segmentNumber); + + if (iter.current == NULL) + { + nitf_Error_initf(error, + NITF_CTXT, + NITF_ERR_INVALID_OBJECT, + "Invalid text segment number"); + goto CATCH_ERROR; + } + + /* Remove from the list */ + segment = (nitf_TextSegment*)nitf_List_remove(record->texts, &iter); + /* Destroy it */ + nitf_TextSegment_destruct(&segment); + + /* Get current num */ + NITF_TRY_GET_UINT32(record->header->NITF_NUMT, &num, error); + + /* If we actually need to resize */ + if (num > 1) + { + /* Make new array, one smaller */ + infoArray = + (nitf_ComponentInfo **) NITF_MALLOC(sizeof(nitf_ComponentInfo *) * + (num - 1)); + + /* Iterate over current infos */ + for (i = 0; i < segmentNumber; ++i) + infoArray[i] = record->header->textInfo[i]; + for (i = segmentNumber + 1; i < num; ++i) + infoArray[i - 1] = record->header->textInfo[i]; + } + + /* Update the num field in the header */ + num--; + + if (!nitf_Field_setUint32(record->header->NITF_NUMT, num, error)) + goto CATCH_ERROR; + /* Delete old one, if there, and set to new one */ + if (record->header->textInfo) + NITF_FREE(record->header->textInfo); + + record->header->textInfo = infoArray; + + /* Update the indexes in any overflow segments */ + if(!fixOverflowIndexes(record,"TXSHD",segmentNumber,error)) + return NITF_FAILURE; + + return NITF_SUCCESS; + +CATCH_ERROR: + + if (infoArray) + NITF_FREE(infoArray); + + return NITF_FAILURE; +} + + +NITFAPI(NITF_BOOL) +nitf_Record_removeDataExtensionSegment(nitf_Record * record, + nitf_Uint32 segmentNumber, + nitf_Error * error) +{ + nitf_Uint32 num; + nitf_ComponentInfo **infoArray = NULL; + nitf_DESegment* segment = NULL; + nitf_Uint32 i; + nitf_ListIterator iter = + nitf_List_at(record->dataExtensions, segmentNumber); + + if (iter.current == NULL) + { + nitf_Error_initf(error, + NITF_CTXT, + NITF_ERR_INVALID_OBJECT, + "Invalid dataExtension segment number"); + goto CATCH_ERROR; + } + + /* Remove from the list */ + segment = (nitf_DESegment*)nitf_List_remove(record->dataExtensions, &iter); + + /* Destroy it */ + nitf_DESegment_destruct(&segment); + + /* Get current num */ + NITF_TRY_GET_UINT32(record->header->NITF_NUMDES, &num, error); + + /* If we actually need to resize */ + if (num > 1) + { + /* Make new array, one smaller */ + infoArray = + (nitf_ComponentInfo **) NITF_MALLOC(sizeof(nitf_ComponentInfo *) * + (num - 1)); + + /* Iterate over current infos */ + for (i = 0; i < segmentNumber; ++i) + { + infoArray[i] = record->header->dataExtensionInfo[i]; + } + for (i = segmentNumber + 1; i < num; ++i) + { + infoArray[i - 1] = record->header->dataExtensionInfo[i]; + } + } + + /* Update the num field in the header */ + num--; + + if (!nitf_Field_setUint32(record->header->NITF_NUMDES, num, error)) + goto CATCH_ERROR; + + /* Delete old one, if there, and set to new one */ + if (record->header->dataExtensionInfo) + { + NITF_FREE(record->header->dataExtensionInfo); + } + record->header->dataExtensionInfo = infoArray; + + /* Fix indexes in other segments with overflows */ + if(!fixSegmentIndexes(record,segmentNumber,error)) + return NITF_FAILURE; + + return NITF_SUCCESS; + +CATCH_ERROR: + return NITF_FAILURE; +} + + +NITFAPI(NITF_BOOL) +nitf_Record_removeReservedExtensionSegment(nitf_Record * record, + nitf_Uint32 segmentNumber, + nitf_Error * error) +{ + nitf_Uint32 num; + nitf_ComponentInfo **infoArray = NULL; + nitf_RESegment* segment = NULL; + nitf_Uint32 i; + + nitf_ListIterator iter = + nitf_List_at(record->reservedExtensions, segmentNumber); + + if (iter.current == NULL) + { + nitf_Error_initf(error, + NITF_CTXT, + NITF_ERR_INVALID_OBJECT, + "Invalid reservedExtension segment number"); + goto CATCH_ERROR; + } + + /* Remove from the list */ + segment = + (nitf_RESegment*)nitf_List_remove(record->reservedExtensions, &iter); + + /* Destroy it */ + nitf_RESegment_destruct(&segment); + + /* Get current num */ + NITF_TRY_GET_UINT32(record->header->NITF_NUMRES, &num, error); + + /* If we actually need to resize */ + if (num > 1) + { + /* Make new array, one smaller */ + infoArray = + (nitf_ComponentInfo **) NITF_MALLOC(sizeof(nitf_ComponentInfo *) * + (num - 1)); + + /* Iterate over current infos */ + for (i = 0; i < segmentNumber; ++i) + { + infoArray[i] = record->header->reservedExtensionInfo[i]; + } + for (i = segmentNumber + 1; i < num; ++i) + { + infoArray[i - 1] = record->header->reservedExtensionInfo[i]; + } + } + + /* Update the num field in the header */ + num--; + + if (!nitf_Field_setUint32(record->header->NITF_NUMRES, num, error)) + goto CATCH_ERROR; + + /* Delete old one, if there, and set to new one */ + if (record->header->reservedExtensionInfo) + { + NITF_FREE(record->header->reservedExtensionInfo); + } + record->header->reservedExtensionInfo = infoArray; + + return NITF_SUCCESS; + +CATCH_ERROR: + + if (infoArray) + { + NITF_FREE( infoArray ); + } + + return NITF_FAILURE; +} + +NITFAPI(NITF_BOOL) nitf_Record_moveImageSegment(nitf_Record * record, + nitf_Uint32 oldIndex, + nitf_Uint32 newIndex, + nitf_Error * error) +{ + nitf_Uint32 num; + nitf_ComponentInfo *tempInfo = NULL; + + NITF_TRY_GET_UINT32(record->header->numImages, &num, error); + + if (oldIndex < 0 || newIndex < 0 || oldIndex >= num || newIndex >= num) + { + nitf_Error_initf(error, + NITF_CTXT, + NITF_ERR_INVALID_OBJECT, + "Invalid index provided"); + goto CATCH_ERROR; + } + + /* Just return OK if no change */ + if (oldIndex == newIndex) + return NITF_SUCCESS; + + /* Do the list move */ + if (nitf_List_move(record->images, oldIndex, newIndex, error)) + goto CATCH_ERROR; + + /* Now, need to move the component info - just move pointers */ + tempInfo = record->header->imageInfo[oldIndex]; + record->header->imageInfo[oldIndex] = record->header->imageInfo[newIndex]; + record->header->imageInfo[newIndex] = tempInfo; + + return NITF_SUCCESS; + + CATCH_ERROR: + return NITF_FAILURE; +} + + +NITFAPI(NITF_BOOL) nitf_Record_moveGraphicSegment(nitf_Record * record, + nitf_Uint32 oldIndex, + nitf_Uint32 newIndex, + nitf_Error * error) +{ + nitf_Uint32 num; + nitf_ComponentInfo *tempInfo = NULL; + + NITF_TRY_GET_UINT32(record->header->numGraphics, &num, error); + + if (oldIndex < 0 || newIndex < 0 || oldIndex >= num || newIndex >= num) + { + nitf_Error_initf(error, + NITF_CTXT, + NITF_ERR_INVALID_OBJECT, + "Invalid index provided"); + goto CATCH_ERROR; + } + + /* Just return OK if no change */ + if (oldIndex == newIndex) + return NITF_SUCCESS; + + /* Do the list move */ + if (nitf_List_move(record->graphics, oldIndex, newIndex, error)) + goto CATCH_ERROR; + + /* Now, need to move the component info - just move pointers */ + tempInfo = record->header->graphicInfo[oldIndex]; + + record->header->graphicInfo[oldIndex] = + record->header->graphicInfo[newIndex]; + + record->header->graphicInfo[newIndex] = tempInfo; + + return NITF_SUCCESS; + +CATCH_ERROR: + return NITF_FAILURE; +} + + +NITFAPI(NITF_BOOL) nitf_Record_moveLabelSegment(nitf_Record * record, + nitf_Uint32 oldIndex, + nitf_Uint32 newIndex, + nitf_Error * error) +{ + nitf_Uint32 num; + nitf_ComponentInfo *tempInfo = NULL; + + NITF_TRY_GET_UINT32(record->header->numLabels, &num, error); + + if (oldIndex < 0 || newIndex < 0 || oldIndex >= num || newIndex >= num) + { + nitf_Error_initf(error, + NITF_CTXT, + NITF_ERR_INVALID_OBJECT, + "Invalid index provided"); + goto CATCH_ERROR; + } + + /* Just return OK if no change */ + if (oldIndex == newIndex) + return NITF_SUCCESS; + + /* Do the list move */ + if (nitf_List_move(record->labels, oldIndex, newIndex, error)) + goto CATCH_ERROR; + + /* Now, need to move the component info - just move pointers */ + tempInfo = record->header->labelInfo[oldIndex]; + record->header->labelInfo[oldIndex] = record->header->labelInfo[newIndex]; + record->header->labelInfo[newIndex] = tempInfo; + + return NITF_SUCCESS; + +CATCH_ERROR: + return NITF_FAILURE; +} + + +NITFAPI(NITF_BOOL) nitf_Record_moveTextSegment(nitf_Record * record, + nitf_Uint32 oldIndex, + nitf_Uint32 newIndex, + nitf_Error * error) +{ + nitf_Uint32 num; + nitf_ComponentInfo *tempInfo = NULL; + + NITF_TRY_GET_UINT32(record->header->numTexts, &num, error); + + if (oldIndex < 0 || newIndex < 0 || oldIndex >= num || newIndex >= num) + { + nitf_Error_initf(error, + NITF_CTXT, + NITF_ERR_INVALID_OBJECT, + "Invalid index provided"); + goto CATCH_ERROR; + } + + /* Just return OK if no change */ + if (oldIndex == newIndex) + return NITF_SUCCESS; + + /* Do the list move */ + if (nitf_List_move(record->texts, oldIndex, newIndex, error)) + goto CATCH_ERROR; + + /* Now, need to move the component info - just move pointers */ + tempInfo = record->header->textInfo[oldIndex]; + record->header->textInfo[oldIndex] = record->header->textInfo[newIndex]; + record->header->textInfo[newIndex] = tempInfo; + + return NITF_SUCCESS; + +CATCH_ERROR: + return NITF_FAILURE; +} + + +NITFAPI(NITF_BOOL) +nitf_Record_moveDataExtensionSegment(nitf_Record * record, + nitf_Uint32 oldIndex, + nitf_Uint32 newIndex, + nitf_Error * error) +{ + nitf_Uint32 num; + nitf_ComponentInfo *tempInfo = NULL; + + NITF_TRY_GET_UINT32(record->header->numDataExtensions, &num, error); + + if (oldIndex < 0 || newIndex < 0 || oldIndex >= num || newIndex >= num) + { + nitf_Error_initf(error, + NITF_CTXT, + NITF_ERR_INVALID_OBJECT, + "Invalid index provided"); + goto CATCH_ERROR; + } + + /* Just return OK if no change */ + if (oldIndex == newIndex) + return NITF_SUCCESS; + + /* Do the list move */ + if (nitf_List_move(record->dataExtensions, oldIndex, newIndex, error)) + goto CATCH_ERROR; + + /* Now, need to move the component info - just move pointers */ + tempInfo = record->header->dataExtensionInfo[oldIndex]; + record->header->dataExtensionInfo[oldIndex] = record->header->dataExtensionInfo[newIndex]; + record->header->dataExtensionInfo[newIndex] = tempInfo; + + return NITF_SUCCESS; + +CATCH_ERROR: + return NITF_FAILURE; +} + + +NITFAPI(NITF_BOOL) +nitf_Record_moveReservedExtensionSegment(nitf_Record * record, + nitf_Uint32 oldIndex, + nitf_Uint32 newIndex, + nitf_Error * error) +{ + nitf_Uint32 num; + nitf_ComponentInfo *tempInfo = NULL; + + NITF_TRY_GET_UINT32(record->header->numReservedExtensions, &num, error); + + if (oldIndex < 0 || newIndex < 0 || oldIndex >= num || newIndex >= num) + { + nitf_Error_initf(error, + NITF_CTXT, + NITF_ERR_INVALID_OBJECT, + "Invalid index provided"); + goto CATCH_ERROR; + } + + /* Just return OK if no change */ + if (oldIndex == newIndex) + return NITF_SUCCESS; + + /* Do the list move */ + if (nitf_List_move(record->reservedExtensions, oldIndex, newIndex, error)) + goto CATCH_ERROR; + + /* Now, need to move the component info - just move pointers */ + tempInfo = record->header->reservedExtensionInfo[oldIndex]; + + record->header->reservedExtensionInfo[oldIndex] = + record->header->reservedExtensionInfo[newIndex]; + + record->header->reservedExtensionInfo[newIndex] = tempInfo; + + return NITF_SUCCESS; + +CATCH_ERROR: + return NITF_FAILURE; +} + +/* + * Ugly macro that is most of the merge logic for a single extension section + * + * This macro is very localized and assumes several local variables exist and + * are initialized. + * + * section - Extended section (i.e., userDefinedSection) + * securityCls - security class field (i.e., imageSecurityClass) + * securityGrp - Security group object (i.e., securityGroup) + * idx - Index field (DE index in original segment) (i.e.,UDOFL) + * typeStr - Type string (i.e.,UDID) + */ + +#define UNMERGE_SEGMENT(section,securityCls,securityGrp,idx,typeStr) \ + length = nitf_Extensions_computeLength(section,version,error); \ + if(length > maxLength) \ + { \ + if(!nitf_Field_get(idx, &overflowIndex, \ + NITF_CONV_INT,NITF_INT32_SZ, error)) \ + { \ + nitf_Error_init(error,\ + "Could not retrieve overflow segment index", \ + NITF_CTXT, NITF_ERR_INVALID_OBJECT); \ + return NITF_FAILURE; \ + } \ + if(overflowIndex == 0) \ + { \ + overflowIndex = addOverflowSegment(record,segIndex,#typeStr, \ + securityCls, securityGrp, &overflow, error); \ + if(overflowIndex == 0) \ + { \ + nitf_Error_init(error, \ + "Could not add overflow segment", \ + NITF_CTXT, NITF_ERR_INVALID_OBJECT); \ + return NITF_FAILURE; \ + } \ + } \ + if(!moveTREs(section, \ + overflow->subheader->userDefinedSection,maxLength,error)) \ + { \ + nitf_Error_init(error, \ + "Could not transfer TREs to overflow segment", \ + NITF_CTXT,NITF_ERR_INVALID_OBJECT); \ + return NITF_FAILURE; \ + } \ + if(!nitf_Field_setUint32(idx, overflowIndex, error)) \ + { \ + nitf_Error_init(error,\ + "Could not set overflow segment index", \ + NITF_CTXT, NITF_ERR_INVALID_OBJECT); \ + return NITF_FAILURE; \ + }\ + } + +NITFAPI(NITF_BOOL) nitf_Record_unmergeTREs(nitf_Record * record, + nitf_Error * error) +{ + /* NITF version */ + nitf_Version version; + + /* File header */ + nitf_FileHeader *header; + + /* Current segment list */ + nitf_ListIterator segIter; + + /* Current segment list end */ + nitf_ListIterator segEnd; + + /* Current segment index */ + nitf_Uint32 segIndex; + + /* Length of TREs in current section */ + nitf_Uint32 length; + + /* Max length for this type of section */ + nitf_Uint32 maxLength; + + /* Overflow index of current extension */ + nitf_Uint32 overflowIndex; + + /* Overflow segment */ + nitf_DESegment *overflow; + + version = nitf_Record_getVersion(record); + + /* File header */ + + maxLength = 99999; + segIndex = 1; /* ??? I moved this up so this would be initialized!! */ + + header = record->header; + UNMERGE_SEGMENT(header->userDefinedSection, + header->classification, + header->securityGroup, + header->NITF_UDHOFL,UDHD); + + UNMERGE_SEGMENT(header->extendedSection, + header->classification, + header->securityGroup, + header->NITF_XHDLOFL,XHD); + + /* Image segments */ + segIter = nitf_List_begin(record->images); + segEnd = nitf_List_end(record->images); + while(nitf_ListIterator_notEqualTo(&segIter, &segEnd)) + { + /* Current subheader */ + nitf_ImageSubheader *subheader; + + maxLength = 99999; + + subheader = (nitf_ImageSubheader *) + ((nitf_ImageSegment *) nitf_ListIterator_get(&segIter))->subheader; + + /* User defined section */ + UNMERGE_SEGMENT(subheader->userDefinedSection, + subheader->imageSecurityClass, + subheader->securityGroup, + subheader->NITF_UDOFL,UDID); + + /* Extension section */ + UNMERGE_SEGMENT(subheader->extendedSection, + subheader->imageSecurityClass, + subheader->securityGroup, + subheader->NITF_IXSOFL,IXSHD); + + segIndex += 1; + nitf_ListIterator_increment(&segIter); + } + + /* Graphics segments */ + segIter = nitf_List_begin(record->graphics); + segEnd = nitf_List_end(record->graphics); + segIndex = 1; + + while(nitf_ListIterator_notEqualTo(&segIter, &segEnd)) + { + /* Current subheader */ + nitf_GraphicSubheader *subheader; + + /* Hello, really? Somebody needs to fix hardcode DP */ + maxLength = 9741; + + subheader = (nitf_GraphicSubheader *) + ((nitf_GraphicSegment *)nitf_ListIterator_get(&segIter))->subheader; + + /* Extension section */ + UNMERGE_SEGMENT(subheader->extendedSection, + subheader->securityClass, + subheader->securityGroup, + subheader->NITF_SXSOFL, + SXSHD); + + segIndex += 1; + nitf_ListIterator_increment(&segIter); + } + + /* Label segments */ + segIter = nitf_List_begin(record->labels); + segEnd = nitf_List_end(record->labels); + segIndex = 1; + + while(nitf_ListIterator_notEqualTo(&segIter, &segEnd)) + { + /* Current subheader */ + nitf_LabelSubheader *subheader; + + /* Fix hardcode! */ + maxLength = 9747; + + subheader = (nitf_LabelSubheader *) + ((nitf_LabelSegment *)nitf_ListIterator_get(&segIter))->subheader; + + /* Extension section */ + + UNMERGE_SEGMENT(subheader->extendedSection, + subheader->securityClass, + subheader->securityGroup, + subheader->NITF_LXSOFL, + LXSHD); + + segIndex += 1; + } + + /* Text segments */ + segIter = nitf_List_begin(record->texts); + segEnd = nitf_List_end(record->texts); + segIndex = 1; + + while(nitf_ListIterator_notEqualTo(&segIter, &segEnd)) + { + /* Current subheader */ + nitf_TextSubheader *subheader; + + /* Fix hardcode! */ + maxLength = 9717; + + subheader = (nitf_TextSubheader *) + ((nitf_TextSegment *) nitf_ListIterator_get(&segIter))->subheader; + + /* Extension section */ + UNMERGE_SEGMENT(subheader->extendedSection, + subheader->securityClass, + subheader->securityGroup, + subheader->NITF_TXSOFL,TXSHD); + + segIndex += 1; + nitf_ListIterator_increment(&segIter); + } + + return NITF_SUCCESS; +} + +NITFAPI(NITF_BOOL) nitf_Record_mergeTREs(nitf_Record * record, + nitf_Error * error) +{ + /* DE segment list */ + nitf_ListIterator deIter; + + /* DE segment list end */ + nitf_ListIterator deEnd; + + /* Current DE segment index (one based) */ + nitf_Uint32 deIndex; + + /* Number of DE segments removed */ + nitf_Int32 deRemoved; + + deIter = nitf_List_begin(record->dataExtensions); + deEnd = nitf_List_end(record->dataExtensions); + deIndex = 1; + deRemoved = 0; + + while(nitf_ListIterator_notEqualTo(&deIter, &deEnd)) + { + /* Current subheader */ + nitf_DESubheader *subheader; + char desid[NITF_DESTAG_SZ+1]; + + /* Owner of overflow */ + nitf_Extensions *destination; + + /* Extended header length field */ + nitf_Field *extLength; + + /* Overflow length field */ + nitf_Field *overflowIndex; + + subheader = (nitf_DESubheader *) + ((nitf_DESegment *)nitf_ListIterator_get(&deIter))->subheader; + + if(!nitf_Field_get(subheader->NITF_DESTAG,(NITF_DATA *) desid, + NITF_CONV_STRING, NITF_DESTAG_SZ+1, error)) + { + nitf_Error_init(error, + "Could not retrieve DE segment id", + NITF_CTXT, NITF_ERR_INVALID_OBJECT); + return NITF_FAILURE; + } + nitf_Field_trimString(desid); + + /* This is an overflow */ + if(strcmp(desid,TRE_OVERFLOW_STR) == 0) + { + nitf_Uint32 segIndex; + char type[NITF_DESOFLW_SZ+1]; + NITF_BOOL eflag; + + /* Get type and index */ + eflag = !nitf_Field_get(subheader->NITF_DESOFLW,(NITF_DATA *) type, + NITF_CONV_STRING,NITF_DESOFLW_SZ+1,error); + eflag |= !nitf_Field_get(subheader->NITF_DESITEM,&segIndex, + NITF_CONV_INT,NITF_INT32_SZ,error); + if(eflag) + { + nitf_Error_init(error, + "Could not retrieve DE segment header overflow value", + NITF_CTXT, NITF_ERR_INVALID_OBJECT); + return NITF_FAILURE; + } + nitf_Field_trimString(type); + + /* File header user defined */ + if(strcmp(type,"UDHD") == 0) + { + extLength = record->header->NITF_UDHDL; + overflowIndex = record->header->NITF_UDHOFL; + destination = record->header->userDefinedSection; + } + /* File header extended */ + else if(strcmp(type, "XHD") == 0) + { + extLength = record->header->NITF_XHDL; + overflowIndex = record->header->NITF_XHDLOFL; + destination = record->header->extendedSection; + } + + /* Image segment */ + else if((strcmp(type, "UDID") == 0) + || (strcmp(type, "IXSHD") == 0)) + { + nitf_ImageSegment *imSeg; + + imSeg = nitf_List_get(record->images,segIndex-1,error); + + /* Image segment user defined */ + if(strcmp(type,"UDID") == 0) + { + extLength = imSeg->subheader->NITF_UDIDL; + overflowIndex = imSeg->subheader->NITF_UDOFL; + destination = imSeg->subheader->userDefinedSection; + } + else + { + extLength = imSeg->subheader->NITF_IXSHDL; + overflowIndex = imSeg->subheader->NITF_IXSOFL; + destination = imSeg->subheader->extendedSection; + } + } + + /* Graphics segment */ + else if(strcmp(type, "SXSHD") == 0) + { + nitf_GraphicSegment *grSeg; + + grSeg = nitf_List_get(record->graphics,segIndex-1,error); + extLength = grSeg->subheader->NITF_SXSHDL; + overflowIndex = grSeg->subheader->NITF_SXSOFL; + destination = grSeg->subheader->extendedSection; + } + + /* Labels segment */ + else if(strcmp(type, "LXSHD") == 0) + { + nitf_LabelSegment *lbSeg; + + lbSeg = nitf_List_get(record->labels,segIndex-1,error); + extLength = lbSeg->subheader->NITF_LXSHDL; + overflowIndex = lbSeg->subheader->NITF_LXSOFL; + destination = lbSeg->subheader->extendedSection; + } + + /* Text segment */ + else if(strcmp(type, "TXSHD") == 0) + { + nitf_TextSegment *txSeg; + + txSeg = nitf_List_get(record->texts,segIndex-1,error); + extLength = txSeg->subheader->NITF_TXSHDL; + overflowIndex = txSeg->subheader->NITF_TXSOFL; + destination = txSeg->subheader->extendedSection; + } + else + { + nitf_Error_init(error, + "Invalid overflow segment type or index", + NITF_CTXT, NITF_ERR_INVALID_OBJECT); + return NITF_FAILURE; + } + + if(!nitf_Field_setUint32(extLength, 0, error)) + return NITF_FAILURE; + if(!nitf_Field_setUint32(overflowIndex, 0, error)) + return NITF_FAILURE; + if(!moveTREs(subheader->userDefinedSection, destination, 0, error)) + return NITF_FAILURE; + + /* Remove the DE segment how does this effect indexes */ + if(!nitf_Record_removeDataExtensionSegment(record,deIndex-1,error)) + return NITF_FAILURE; + + deIter = nitf_List_begin(record->dataExtensions); + deIndex = 1; + deRemoved += 1; + continue; + } + + deIndex += 1; + nitf_ListIterator_increment(&deIter); + } + + return NITF_SUCCESS; +} diff --git a/modules/c/nitf/source/RowSource.c b/modules/c/nitf/source/RowSource.c new file mode 100644 index 000000000..2f16cc971 --- /dev/null +++ b/modules/c/nitf/source/RowSource.c @@ -0,0 +1,185 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +/* + * Implementation of the row source object + */ + +#include "nitf/RowSource.h" + +/* The instance data for the rowSource object */ + +typedef struct _RowSourceImpl +{ + /* Saved constructor arguments */ + void *algorithm; /* The algorithm object */ + /* Pointer to the next row function */ + NITF_ROW_SOURCE_NEXT_ROW nextRow; + nitf_Uint32 band; /* Associate output band */ + nitf_Uint32 numRows; /* Number of rows */ + nitf_Uint32 rowLength; /* Length of each row in bytes (single band) */ + + nitf_Uint8 *rowBuffer; /* The row buffer */ + nitf_Uint8 *nextPtr; /* Points to next byte to be transfered */ + nitf_Uint64 bytesLeft; /* Bytes left to be processed */ +} +RowSourceImpl; + +/* + * RowSource_read - Read data function for row source + */ + +/* Instance data */ +/* Output buffer */ +NITFPRIV(NITF_BOOL) RowSource_read(NITF_DATA * data, char *buf, nitf_Off size, /* Amount to read */ + nitf_Error * error) /* For error returns */ +{ + RowSourceImpl *impl; /* Instance data */ + nitf_Uint64 xfrCount; /* Transfer count */ + nitf_Uint64 remainder; /* Amount left to transfer */ + char *bufPtr; /* Current location in output buffer */ + + impl = (RowSourceImpl *) data; + + remainder = size; + bufPtr = buf; + while (remainder > 0) + { + if (impl->bytesLeft == 0) /* Need more data */ + { + if (!((*(impl->nextRow)) (impl->algorithm, + impl->band, impl->rowBuffer, error))) + return (NITF_FAILURE); + impl->bytesLeft = impl->rowLength; + impl->nextPtr = impl->rowBuffer; + } + + xfrCount = + (remainder <= impl->bytesLeft) ? remainder : impl->bytesLeft; + + /* Transfer data */ + memcpy(bufPtr, impl->nextPtr, xfrCount); + + impl->nextPtr += xfrCount; /* Update pointers and counts */ + bufPtr += xfrCount; + impl->bytesLeft -= xfrCount; + remainder -= xfrCount; + } + + return (NITF_SUCCESS); +} + + +/* + * RowSource_destruct - Destructor for instance data + */ + +/* Instance data to destroy */ +NITFPRIV(void) RowSource_destruct(NITF_DATA * data) +{ + RowSourceImpl *impl = (RowSourceImpl *) data; + if (impl) + { + if (impl->rowBuffer != NULL) + NITF_FREE(impl->rowBuffer); + NITF_FREE(impl); + } +} + + +NITFPRIV(nitf_Off) RowSource_getSize(NITF_DATA * data, nitf_Error *e) +{ + RowSourceImpl *impl = (RowSourceImpl *) data; + return (nitf_Off)impl->numRows * (nitf_Off)impl->rowLength; +} + +NITFPRIV(NITF_BOOL) RowSource_setSize(NITF_DATA * data, nitf_Off size, nitf_Error *e) +{ + return NITF_SUCCESS; +} + + +/* BandSource interface structure, static is ok since this is read-only */ + +static nitf_IDataSource iRowSource = + { + RowSource_read, + RowSource_destruct, + RowSource_getSize, + RowSource_setSize + }; + +/*========================= nitf_RowSource_construct =====================*/ + +NITFAPI(nitf_BandSource *) nitf_RowSource_construct(void *algorithm, + NITF_ROW_SOURCE_NEXT_ROW + nextRow, + nitf_Uint32 band, + nitf_Uint32 numRows, + nitf_Uint32 rowLength, + nitf_Error * error) +{ + nitf_BandSource *source; /* The result */ + RowSourceImpl *impl; /* Instance data */ + + /* Allocate and initialize instance data */ + + impl = (RowSourceImpl *) NITF_MALLOC(sizeof(RowSourceImpl)); + if (impl == NULL) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + return NULL; + } + + impl->algorithm = algorithm; + impl->nextRow = nextRow; + impl->band = band; + impl->numRows = numRows; + impl->rowLength = rowLength; + + impl->rowBuffer = (NITF_DATA *) NITF_MALLOC(rowLength); + if (impl->rowBuffer == NULL) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + RowSource_destruct(impl); + return (NULL); + } + + impl->nextPtr = impl->rowBuffer; + impl->bytesLeft = 0; + + /* Allocate and initialize result */ + + source = (nitf_BandSource *) NITF_MALLOC(sizeof(nitf_BandSource)); + if (source == NULL) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + return NULL; + } + + source->data = impl; + source->iface = &iRowSource; + return (source); +} diff --git a/modules/c/nitf/source/SegmentReader.c b/modules/c/nitf/source/SegmentReader.c new file mode 100644 index 000000000..b0e0c43e3 --- /dev/null +++ b/modules/c/nitf/source/SegmentReader.c @@ -0,0 +1,145 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/SegmentReader.h" + +NITFAPI(NITF_BOOL) nitf_SegmentReader_read(nitf_SegmentReader * + segmentReader, + NITF_DATA * buffer, + size_t count, + nitf_Error * error) +{ + NITF_BOOL ret; /* Return value */ + + /* Check for request out of bounds */ + if (count + segmentReader->virtualOffset > segmentReader->dataLength) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_INVALID_PARAMETER, + "Seek offset out of bounds"); + return (NITF_FAILURE); + } + + /* + Do the read via IOHandle_read. If the virtaul offset is 0 seek to the + baseOffset first. This handles the initial read. If the offset is not + 0 assume the file is positioned to the correct place + + */ + if (segmentReader->virtualOffset == 0) + if (!NITF_IO_SUCCESS(nitf_IOInterface_seek(segmentReader->input, + segmentReader->baseOffset, + NITF_SEEK_SET, error))) + return (NITF_FAILURE); + + ret = nitf_IOInterface_read + (segmentReader->input, (char *) buffer, count, error); + segmentReader->virtualOffset += count; + return ret; +} + + +NITFAPI(nitf_Off) nitf_SegmentReader_seek(nitf_SegmentReader * segmentReader, + nitf_Off offset, + int whence, nitf_Error * error) +{ + nitf_Uint64 baseOffset; /* Bas offset to the data */ + nitf_Off actualPosition; /* Real file position (no base offset) */ + + baseOffset = segmentReader->baseOffset; + + /* Check for request out of bounds */ + switch (whence) + { + case NITF_SEEK_SET: + if ((offset > segmentReader->dataLength) || (offset < 0)) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_INVALID_PARAMETER, + "Seek offset out of bounds\n"); + return ((nitf_Off) - 1); + } + actualPosition = offset + baseOffset; + break; + case NITF_SEEK_CUR: + if ((offset + segmentReader->virtualOffset > + segmentReader->dataLength) + || (offset + segmentReader->virtualOffset < 0)) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_INVALID_PARAMETER, + "Seek offset out of bounds\n"); + return ((nitf_Off) - 1); + } + actualPosition = + offset + segmentReader->virtualOffset + baseOffset; + break; + case NITF_SEEK_END: + if ((offset + segmentReader->dataLength > + segmentReader->dataLength) + || (offset + segmentReader->dataLength < 0)) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_INVALID_PARAMETER, + "Seek offset out of bounds\n"); + return ((nitf_Off) - 1); + } + actualPosition = offset + segmentReader->dataLength + baseOffset; + break; + default: + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_INVALID_PARAMETER, + "Invalid seek\n"); + return ((nitf_Off) - 1); + } + + actualPosition = + nitf_IOInterface_seek(segmentReader->input, + actualPosition, NITF_SEEK_SET, error); + + if (!NITF_IO_SUCCESS(actualPosition)) + return (actualPosition); + + segmentReader->virtualOffset = + actualPosition - segmentReader->baseOffset; + + return segmentReader->virtualOffset; +} + + +NITFAPI(nitf_Off) nitf_SegmentReader_tell(nitf_SegmentReader * segmentReader, + nitf_Error * error) +{ + return (segmentReader->virtualOffset); +} + + +NITFAPI(nitf_Off) nitf_SegmentReader_getSize(nitf_SegmentReader * + segmentReader, + nitf_Error * error) +{ + return (segmentReader->dataLength); +} + + +NITFAPI(void) nitf_SegmentReader_destruct(nitf_SegmentReader ** + segmentReader) +{ + if ((*segmentReader) != NULL) + NITF_FREE(*segmentReader); + return; +} diff --git a/modules/c/nitf/source/SegmentSource.c b/modules/c/nitf/source/SegmentSource.c new file mode 100644 index 000000000..c2770edbe --- /dev/null +++ b/modules/c/nitf/source/SegmentSource.c @@ -0,0 +1,520 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + +#include "nitf/SegmentSource.h" + +/* + * Private implementation struct + */ +typedef struct _MemorySourceImpl +{ + const char *data; + NITF_BOOL ownData; + nitf_Off size; + int sizeSet; + nitf_Off mark; + int byteSkip; + nitf_Off start; +} +MemorySourceImpl; + + +NITFPRIV(MemorySourceImpl *) toMemorySource(NITF_DATA * data, + nitf_Error * error) +{ + MemorySourceImpl *memorySource = (MemorySourceImpl *) data; + if (memorySource == NULL) + { + nitf_Error_init(error, "Null pointer reference", + NITF_CTXT, NITF_ERR_INVALID_OBJECT); + return NULL; + } + return memorySource; +} + + +NITFPRIV(NITF_BOOL) MemorySource_contigRead(MemorySourceImpl * + memorySource, char *buf, + nitf_Off size, + nitf_Error * error) +{ + memcpy(buf, memorySource->data + memorySource->mark, size); + memorySource->mark += size; + return NITF_SUCCESS; +} + + +NITFPRIV(NITF_BOOL) MemorySource_offsetRead(MemorySourceImpl * + memorySource, char *buf, + nitf_Off size, + nitf_Error * error) +{ + int i = 0; + + while (i < size) + { + buf[i++] = *(memorySource->data + memorySource->mark++); + memorySource->mark += (memorySource->byteSkip); + } + return NITF_SUCCESS; +} + + +/* + * Private read implementation for memory source. + */ +NITFPRIV(NITF_BOOL) MemorySource_read(NITF_DATA * data, + char *buf, + nitf_Off size, nitf_Error * error) +{ + MemorySourceImpl *memorySource = toMemorySource(data, error); + if (!memorySource) + return NITF_FAILURE; + + /* We like the contiguous read case, it's fast */ + /* We want to make sure we reward this case */ + if (memorySource->byteSkip == 0) + return MemorySource_contigRead(memorySource, buf, size, error); + + return MemorySource_offsetRead(memorySource, buf, size, error); +} + + +NITFPRIV(void) MemorySource_destruct(NITF_DATA * data) +{ + MemorySourceImpl *memorySource = (MemorySourceImpl *) data; + if (memorySource) + { + if (memorySource->ownData) + { + NITF_FREE((void*)memorySource->data); + } + NITF_FREE(memorySource); + } +} + +NITFPRIV(nitf_Off) MemorySource_getSize(NITF_DATA * data, nitf_Error *e) +{ + MemorySourceImpl *memorySource = (MemorySourceImpl *) data; + assert(memorySource); + return memorySource->sizeSet ? (nitf_Off)memorySource->size : + (nitf_Off)(memorySource->size / (memorySource->byteSkip + 1)); +} + +NITFPRIV(NITF_BOOL) MemorySource_setSize(NITF_DATA * data, nitf_Off size, nitf_Error *e) +{ + MemorySourceImpl *memorySource = (MemorySourceImpl *) data; + assert(memorySource); + memorySource->size = size; + memorySource->sizeSet = 1; + return NITF_SUCCESS; +} + + +NITFAPI(nitf_SegmentSource *) nitf_SegmentMemorySource_construct +( + const char* data, + nitf_Off size, + nitf_Off start, + int byteSkip, + NITF_BOOL copyData, + nitf_Error* error +) +{ + static nitf_IDataSource iMemorySource = + { + &MemorySource_read, + &MemorySource_destruct, + &MemorySource_getSize, + &MemorySource_setSize + }; + MemorySourceImpl *impl = NULL; + nitf_SegmentSource *segmentSource = NULL; + + impl = (MemorySourceImpl *) NITF_MALLOC(sizeof(MemorySourceImpl)); + if (!impl) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), NITF_CTXT, + NITF_ERR_MEMORY); + return NULL; + } + + if (copyData) + { + char* dataCopy = (char*) NITF_MALLOC(size); + + if (!dataCopy) + { + NITF_FREE(impl); + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), NITF_CTXT, + NITF_ERR_MEMORY); + return NULL; + } + memcpy(dataCopy, data, size); + + impl->data = dataCopy; + impl->ownData = 1; + } + else + { + impl->data = data; + impl->ownData = 0; + } + impl->size = size; + impl->sizeSet = 0; + impl->mark = impl->start = (start >= 0 ? start : 0); + impl->byteSkip = byteSkip >= 0 ? byteSkip : 0; + + segmentSource = (nitf_SegmentSource *) NITF_MALLOC(sizeof(nitf_SegmentSource)); + if (!segmentSource) + { + if (copyData) + { + NITF_FREE((void*)impl->data); + } + NITF_FREE(impl); + + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), NITF_CTXT, + NITF_ERR_MEMORY); + return NULL; + } + segmentSource->data = impl; + segmentSource->iface = &iMemorySource; + return segmentSource; +} + + +/* + * Private implementation struct + */ +typedef struct _FileSourceImpl +{ + nitf_IOInterface *io; + nitf_Off start; + nitf_Off size; + nitf_Off fileSize; + int byteSkip; + nitf_Off mark; +} +FileSourceImpl; + +NITFPRIV(void) FileSource_destruct(NITF_DATA * data) +{ + nitf_Error error; + if (data) + { + FileSourceImpl *fileSource = (FileSourceImpl *) data; + if (fileSource->io) + { + nrt_IOInterface_close(fileSource->io, &error); + nrt_IOInterface_destruct(&fileSource->io); + fileSource->io = NULL; + } + NITF_FREE(data); + } +} + +NITFPRIV(nitf_Off) FileSource_getSize(NITF_DATA * data, nitf_Error *e) +{ + FileSourceImpl *fileSource = (FileSourceImpl *) data; + assert(fileSource); + assert(fileSource->fileSize > fileSource->start); + return fileSource->size; +} + +NITFPRIV(NITF_BOOL) FileSource_setSize(NITF_DATA* data, nitf_Off size, nitf_Error *e) +{ + /* you better know what you're doing if you set the size yourself! */ + FileSourceImpl* fileSource = (FileSourceImpl*)data; + assert(fileSource); + assert(fileSource->fileSize >= size); + fileSource->size = size; + return NITF_SUCCESS; +} + +NITFPRIV(FileSourceImpl *) toFileSource(NITF_DATA * data, + nitf_Error * error) +{ + FileSourceImpl *fileSource = (FileSourceImpl *) data; + if (fileSource == NULL) + { + nitf_Error_init(error, "Null pointer reference", + NITF_CTXT, NITF_ERR_INVALID_OBJECT); + return NULL; + } + return fileSource; +} + + +NITFPRIV(NITF_BOOL) FileSource_contigRead(FileSourceImpl * fileSource, + char *buf, + nitf_Off size, nitf_Error * error) +{ + if (!NITF_IO_SUCCESS(nitf_IOInterface_read(fileSource->io, buf, size, + error))) + return NITF_FAILURE; + fileSource->mark += size; + return NITF_SUCCESS; +} + + +/* + * The idea here is we will speed it up by creating a temporary buffer + * for reading from the io handle. Even with the allocation, this should + * be much faster than seeking every time. + * + * The basic idea is that we allocate the temporary buffer to the request + * size * the skip factor. It should be noted that the tradeoff here is that, + * for very large read values, this may be really undesirable, especially for + * large skip factors. + * + * If this proves to be a problem, I will revert it back to a seek/read paradigm + * -DP + */ +NITFPRIV(NITF_BOOL) FileSource_offsetRead(FileSourceImpl * fileSource, + char *buf, + nitf_Off size, nitf_Error * error) +{ + + nitf_Off tsize = size * (fileSource->byteSkip + 1); + + char *tbuf; + nitf_Off lmark = 0; + int i = 0; + if (tsize + fileSource->mark > fileSource->size) + tsize = fileSource->size - fileSource->mark; + + tbuf = (char *) NITF_MALLOC(tsize); + if (!tbuf) + { + nitf_Error_init(error, + NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + return NITF_FAILURE; + } + + if (!nitf_IOInterface_read(fileSource->io, tbuf, tsize, error)) + { + NITF_FREE(tbuf); + return NITF_FAILURE; + } + /* Downsize for buf */ + while (i < size) + { + buf[i++] = *(tbuf + lmark++); + lmark += (fileSource->byteSkip); + } + fileSource->mark += lmark; + NITF_FREE(tbuf); + return NITF_SUCCESS; +} + + +/* + * Private read implementation for file source. + */ +NITFPRIV(NITF_BOOL) FileSource_read(NITF_DATA * data, + char *buf, + nitf_Off size, nitf_Error * error) +{ + FileSourceImpl *fileSource = toFileSource(data, error); + if (!fileSource) + return NITF_FAILURE; + + if (!NITF_IO_SUCCESS(nitf_IOInterface_seek(fileSource->io, + fileSource->mark, + NITF_SEEK_SET, error))) + return NITF_FAILURE; + if (fileSource->byteSkip == 0) + return FileSource_contigRead(fileSource, buf, size, error); + return FileSource_offsetRead(fileSource, buf, size, error); +} + + +NITFAPI(nitf_SegmentSource *) nitf_SegmentFileSource_construct +( + nitf_IOHandle handle, + nitf_Off start, + int byteSkip, + nitf_Error * error +) +{ + static nitf_IDataSource iFileSource = + { + &FileSource_read, + &FileSource_destruct, + &FileSource_getSize, + &FileSource_setSize + }; + FileSourceImpl *impl = NULL; + nitf_SegmentSource *segmentSource = NULL; + + impl = (FileSourceImpl *) NITF_MALLOC(sizeof(FileSourceImpl)); + if (!impl) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), NITF_CTXT, + NITF_ERR_MEMORY); + return NULL; + } + if (!(impl->io = nitf_IOHandleAdapter_construct(handle, + NRT_ACCESS_READONLY, + error))) + return NULL; + + impl->byteSkip = byteSkip >= 0 ? byteSkip : 0; + impl->mark = impl->start = (start >= 0 ? start : 0); + impl->fileSize = nitf_IOInterface_getSize(impl->io, error); + + if (!NITF_IO_SUCCESS(impl->fileSize)) + { + NITF_FREE(impl); + return NULL; + } + + /* figure out the actual # oif bytes represented by the source */ + impl->size = impl->fileSize / (impl->byteSkip + 1); + + segmentSource = (nitf_SegmentSource *) NITF_MALLOC(sizeof(nitf_SegmentSource)); + if (!segmentSource) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), NITF_CTXT, + NITF_ERR_MEMORY); + return NULL; + } + segmentSource->data = impl; + segmentSource->iface = &iFileSource; + return segmentSource; +} + + +NITFAPI(nitf_SegmentSource *) nitf_SegmentFileSource_constructIO +( + nitf_IOInterface* io, + nitf_Off start, + int byteSkip, + nitf_Error * error +) +{ + static nitf_IDataSource iFileSource = + { + &FileSource_read, + &FileSource_destruct, + &FileSource_getSize, + &FileSource_setSize + }; + FileSourceImpl *impl = NULL; + nitf_SegmentSource *segmentSource = NULL; + + impl = (FileSourceImpl *) NITF_MALLOC(sizeof(FileSourceImpl)); + if (!impl) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), NITF_CTXT, + NITF_ERR_MEMORY); + return NULL; + } + impl->io = io; + impl->byteSkip = byteSkip >= 0 ? byteSkip : 0; + impl->mark = impl->start = (start >= 0 ? start : 0); + impl->fileSize = nitf_IOInterface_getSize(impl->io, error); + + if (!NITF_IO_SUCCESS(impl->fileSize)) + { + NITF_FREE(impl); + return NULL; + } + + /* figure out the actual # oif bytes represented by the source */ + impl->size = impl->fileSize / (impl->byteSkip + 1); + + segmentSource = (nitf_SegmentSource *) NITF_MALLOC(sizeof(nitf_SegmentSource)); + if (!segmentSource) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), NITF_CTXT, + NITF_ERR_MEMORY); + return NULL; + } + segmentSource->data = impl; + segmentSource->iface = &iFileSource; + return segmentSource; +} + + +NITFPRIV(void) SegmentReader_destruct(NITF_DATA * data) +{ + /* nothing... */ +} + +NITFPRIV(nitf_Off) SegmentReader_getSize(NITF_DATA * data, nitf_Error *e) +{ + nitf_SegmentReader *reader = (nitf_SegmentReader*)data; + assert(reader); + return reader->dataLength; +} + +NITFPRIV(NITF_BOOL) SegmentReader_setSize(NITF_DATA* data, nitf_Off size, nitf_Error *e) +{ + /* does nothing... - should we return an error instead? */ + return NITF_SUCCESS; +} + + +/* + * Private read implementation for file source. + */ +NITFPRIV(NITF_BOOL) SegmentReader_read(NITF_DATA * data, + char *buf, + nitf_Off size, nitf_Error * error) +{ + nitf_SegmentReader *reader = (nitf_SegmentReader*)data; + assert(reader); + return nitf_SegmentReader_read(reader, buf, (size_t)size, error); +} + + +NITFAPI(nitf_SegmentSource *) nitf_SegmentReaderSource_construct +( + nitf_SegmentReader *reader, + nitf_Error * error +) +{ + static nitf_IDataSource iSource = + { + &SegmentReader_read, + &SegmentReader_destruct, + &SegmentReader_getSize, + &SegmentReader_setSize + }; + nitf_SegmentSource *segmentSource = NULL; + + segmentSource = (nitf_SegmentSource *) NITF_MALLOC(sizeof(nitf_SegmentSource)); + if (!segmentSource) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), NITF_CTXT, + NITF_ERR_MEMORY); + return NULL; + } + segmentSource->data = reader; + segmentSource->iface = &iSource; + return segmentSource; +} diff --git a/modules/c/nitf/source/SegmentWriter.c b/modules/c/nitf/source/SegmentWriter.c new file mode 100644 index 000000000..37a8e62e1 --- /dev/null +++ b/modules/c/nitf/source/SegmentWriter.c @@ -0,0 +1,157 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/SegmentWriter.h" + +#define READ_SIZE 8192 + + + +/* + * Private implementation struct + */ +typedef struct _SegmentWriterImpl +{ + nitf_SegmentSource *segmentSource; +} SegmentWriterImpl; + + + +NITFPRIV(void) SegmentWriter_destruct(NITF_DATA * data) +{ + SegmentWriterImpl *impl = (SegmentWriterImpl *) data; + + if (impl) + { + if (impl->segmentSource) + nitf_SegmentSource_destruct(&impl->segmentSource); + NITF_FREE(impl); + } +} + + +NITFPRIV(NITF_BOOL) SegmentWriter_write(NITF_DATA * data, + nitf_IOInterface* io, + nitf_Error * error) +{ + size_t size, bytesLeft; + size_t readSize = READ_SIZE; + size_t bytesToRead = READ_SIZE; + char* buf = NULL; + SegmentWriterImpl *impl = (SegmentWriterImpl *) data; + + size = (*impl->segmentSource->iface->getSize)(impl->segmentSource->data, error); + bytesLeft = size; + + buf = (char*) NITF_MALLOC(readSize); + if (!buf) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), NITF_CTXT, + NITF_ERR_MEMORY); + goto CATCH_ERROR; + } + + while (bytesLeft > 0) + { + if (bytesLeft < readSize) + bytesToRead = (size_t)bytesLeft; + else + bytesToRead = readSize; + + /* read the bytes */ + if (!(*(impl->segmentSource->iface->read)) + (impl->segmentSource->data, buf, bytesToRead, error)) + { + goto CATCH_ERROR; + } + + /* write them */ + if (!nitf_IOInterface_write(io, buf, (int)bytesToRead, error)) + goto CATCH_ERROR; + bytesLeft -= bytesToRead; + } + + NITF_FREE(buf); + return NITF_SUCCESS; + +CATCH_ERROR: + if (buf) NITF_FREE(buf); + return NITF_FAILURE; +} + + + +NITFAPI(nitf_SegmentWriter *) nitf_SegmentWriter_construct(nitf_Error *error) +{ + static nitf_IWriteHandler iWriteHandler = + { + &SegmentWriter_write, + &SegmentWriter_destruct + }; + + SegmentWriterImpl *impl = NULL; + nitf_SegmentWriter *segmentWriter = NULL; + + impl = (SegmentWriterImpl *) NITF_MALLOC(sizeof(SegmentWriterImpl)); + if (!impl) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), NITF_CTXT, + NITF_ERR_MEMORY); + goto CATCH_ERROR; + } + impl->segmentSource = NULL; + + segmentWriter = (nitf_SegmentWriter *) NITF_MALLOC(sizeof(nitf_SegmentWriter)); + if (!segmentWriter) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), NITF_CTXT, + NITF_ERR_MEMORY); + goto CATCH_ERROR; + } + segmentWriter->data = impl; + segmentWriter->iface = &iWriteHandler; + return segmentWriter; + + CATCH_ERROR: + if (impl) + NITF_FREE(impl); + return NULL; +} + + +NITFAPI(NITF_BOOL) nitf_SegmentWriter_attachSource +( + nitf_SegmentWriter * segmentWriter, + nitf_SegmentSource * segmentSource, + nitf_Error * error +) +{ + SegmentWriterImpl *impl = (SegmentWriterImpl *) segmentWriter->data; + if (impl->segmentSource != NULL) + { + nitf_Error_init(error, "Segment source already attached", + NITF_CTXT, NITF_ERR_INVALID_PARAMETER); + return NITF_FAILURE; + } + impl->segmentSource = segmentSource; + return NITF_SUCCESS; +} diff --git a/modules/c/nitf/source/StreamIOWriteHandler.c b/modules/c/nitf/source/StreamIOWriteHandler.c new file mode 100644 index 000000000..ee0f0dc62 --- /dev/null +++ b/modules/c/nitf/source/StreamIOWriteHandler.c @@ -0,0 +1,157 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; + * If not, see . + * + */ + +#include "nitf/StreamIOWriteHandler.h" + + +typedef struct _WriteHandlerImpl +{ + nitf_IOInterface* ioHandle; + nitf_Uint64 offset; + nitf_Uint64 bytes; +} WriteHandlerImpl; + + +#define _STREAM_CHUNK_SIZE 8192 + +/* + * Private read implementation for file source. + */ +NITFPRIV(NITF_BOOL) WriteHandler_write + (NITF_DATA * data, nitf_IOInterface* output, nitf_Error * error) +{ + WriteHandlerImpl *impl = NULL; + nitf_Uint64 toWrite; + nitf_Uint32 bytesThisPass; + char *buf = NULL; + + /* cast it to the structure we know about */ + impl = (WriteHandlerImpl *) data; + + buf = (char*)NITF_MALLOC(_STREAM_CHUNK_SIZE); + if (!buf) + { + nitf_Error_init(error, NITF_STRERROR( NITF_ERRNO ), + NITF_CTXT, NITF_ERR_MEMORY); + return NITF_FAILURE; + } + + /* stream the input to the output in chunks */ + + /* first, seek to the right spot of the input handle */ + if (!NITF_IO_SUCCESS( + nitf_IOInterface_seek( + impl->ioHandle, impl->offset, NITF_SEEK_SET, error + ) + ) + ) + goto CATCH_ERROR; + + toWrite = impl->bytes; + while (toWrite > 0) + { + bytesThisPass = toWrite >= _STREAM_CHUNK_SIZE ? _STREAM_CHUNK_SIZE : + (nitf_Uint32) toWrite; + + /* read */ + if (!nitf_IOInterface_read(impl->ioHandle, buf, bytesThisPass, error)) + goto CATCH_ERROR; + + /* write */ + if (!nitf_IOInterface_write(output, buf, bytesThisPass, error)) + goto CATCH_ERROR; + + /* update count */ + toWrite -= bytesThisPass; + } + + NITF_FREE(buf); + + return NITF_SUCCESS; + + CATCH_ERROR: + if (buf) + NITF_FREE(buf); + return NITF_FAILURE; +} + + +NITFPRIV(void) WriteHandler_destruct(NITF_DATA * data) +{ + if (data) + { + WriteHandlerImpl *impl = (WriteHandlerImpl*)data; + NITF_FREE(impl); + } +} + + +NITFAPI(nitf_WriteHandler*) +nitf_StreamIOWriteHandler_construct(nitf_IOInterface *ioHandle, + nitf_Uint64 offset, + nitf_Uint64 bytes, + nitf_Error *error) +{ + nitf_WriteHandler *writeHandler = NULL; + WriteHandlerImpl *impl = NULL; + + /* make the interface */ + static nitf_IWriteHandler iWriteHandler = { + &WriteHandler_write, + &WriteHandler_destruct + }; + + /* construct the persisent one */ + impl = (WriteHandlerImpl *) NITF_MALLOC(sizeof(WriteHandlerImpl)); + if (!impl) + { + nitf_Error_init(error, NITF_STRERROR( NITF_ERRNO ), + NITF_CTXT, NITF_ERR_MEMORY); + goto CATCH_ERROR; + } + + impl->ioHandle = ioHandle; + impl->offset = offset; + impl->bytes = bytes; + + writeHandler = + (nitf_WriteHandler *) NITF_MALLOC(sizeof(nitf_WriteHandler)); + + if (!writeHandler) + { + nitf_Error_init(error, NITF_STRERROR( NITF_ERRNO ), + NITF_CTXT, NITF_ERR_MEMORY); + goto CATCH_ERROR; + } + writeHandler->data = impl; + writeHandler->iface = &iWriteHandler; + + /* return successfully */ + return writeHandler; + + CATCH_ERROR: + if (writeHandler) + nitf_WriteHandler_destruct(&writeHandler); + if (impl) + NITF_FREE(impl); + return NULL; +} diff --git a/modules/c/nitf/source/SubWindow.c b/modules/c/nitf/source/SubWindow.c new file mode 100644 index 000000000..1e2251d6a --- /dev/null +++ b/modules/c/nitf/source/SubWindow.c @@ -0,0 +1,68 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/SubWindow.h" + +NITFAPI(nitf_SubWindow *) nitf_SubWindow_construct(nitf_Error * error) +{ + nitf_SubWindow *subWindow = + (nitf_SubWindow *) NITF_MALLOC(sizeof(nitf_SubWindow)); + if (!subWindow) + { + nitf_Error_init(error, + NITF_STRERROR(NITF_ERRNO), NITF_CTXT, + NITF_ERR_MEMORY); + return NULL; + } + + subWindow->startRow = 0; + subWindow->startCol = 0; + subWindow->numRows = 0; + subWindow->numCols = 0; + + subWindow->bandList = NULL; + subWindow->numBands = 0; + + subWindow->downsampler = NULL; + + return subWindow; +} + + +NITFAPI(NITF_BOOL) nitf_SubWindow_setDownSampler(nitf_SubWindow *subWindow, + nitf_DownSampler *downsampler, + nitf_Error * error) +{ + assert(subWindow); + subWindow->downsampler = downsampler; + return NITF_SUCCESS; +} + + +NITFAPI(void) nitf_SubWindow_destruct(nitf_SubWindow ** subWindow) +{ + if (*subWindow) + { + NITF_FREE(*subWindow); + *subWindow = NULL; + } +} diff --git a/modules/c/nitf/source/TRE.c b/modules/c/nitf/source/TRE.c new file mode 100644 index 000000000..001401844 --- /dev/null +++ b/modules/c/nitf/source/TRE.c @@ -0,0 +1,193 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/TRE.h" +#include "nitf/PluginRegistry.h" + + +/* IF desc is null, look for it, if I can't load then fail */ +NITFAPI(nitf_TRE *) nitf_TRE_createSkeleton(const char* tag, + nitf_Error* error) +{ + int toCopy = NITF_MAX_TAG; + nitf_TRE *tre = (nitf_TRE *) NITF_MALLOC(sizeof(nitf_TRE)); + + if (!tre) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + return NULL; + } + + /* Just in case the first malloc fails */ + tre->handler = NULL; + tre->priv = NULL; + + /* This happens with things like "DES" */ + if (strlen(tag) < NITF_MAX_TAG ) + { + toCopy = strlen(tag); + } + memset(tre->tag, 0, NITF_MAX_TAG + 1); + memcpy(tre->tag, tag, toCopy); + + return tre; +} + + +NITFAPI(nitf_TRE *) nitf_TRE_clone(nitf_TRE* source, nitf_Error* error) +{ + nitf_TRE *tre = NULL; + + if (source) + { + tre = (nitf_TRE *) NITF_MALLOC(sizeof(nitf_TRE)); + if (!tre) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + return NULL; + } + + /* share the handler */ + tre->handler = source->handler; + memcpy(tre->tag, source->tag, sizeof(tre->tag)); + + /* call the handler clone method, if one is defined */ + if (tre->handler && tre->handler->clone) + { + if (!tre->handler->clone(source, tre, error)) + { + nitf_TRE_destruct(&tre); + return NULL; + } + } + } + else + { + nitf_Error_initf(error, + NITF_CTXT, + NITF_ERR_INVALID_OBJECT, + "Trying to clone NULL pointer"); + } + return tre; +} + + + +NITFAPI(void) nitf_TRE_destruct(nitf_TRE ** tre) +{ + if (*tre) + { + if ((*tre)->handler && (*tre)->handler->destruct) + { + /* let the handler destroy the private data */ + (*tre)->handler->destruct(*tre); + } + + NITF_FREE(*tre); + *tre = NULL; + } +} +NITFAPI(nitf_TREHandler*) nitf_DefaultTRE_handler(nitf_Error * error); + + +NITFAPI(nitf_TRE *) nitf_TRE_construct(const char* tag, + const char* id, + nitf_Error * error) +{ + int bad = 0; + nitf_TRE* tre = nitf_TRE_createSkeleton(tag, error); + nitf_PluginRegistry *reg = nitf_PluginRegistry_getInstance(error); + + if (!tre) + return NULL; + if (!reg) + return NULL; + + tre->handler = NULL; + /* if it's not a RAW id, try to load it from the registry */ + if (!id || strcmp(id, NITF_TRE_RAW) != 0) + { + tre->handler = + nitf_PluginRegistry_retrieveTREHandler(reg, tag, &bad, error); + + if (bad) + return NULL; + } + if (!tre->handler) + { + tre->handler = nitf_DefaultTRE_handler(error); + if (!tre->handler) + return NULL; + } + + if (tre->handler->init && !(tre->handler->init)(tre, id, error)) + { + nitf_TRE_destruct(&tre); + return NULL; + } + return tre; +} + +NITFAPI(nitf_TREEnumerator*) nitf_TRE_begin(nitf_TRE* tre, nitf_Error* error) +{ + return tre->handler->begin(tre, error); +} + +NITFAPI(NITF_BOOL) nitf_TRE_exists(nitf_TRE * tre, const char *tag) +{ + return (!tre) ? NITF_FAILURE : + (nitf_TRE_getField(tre, tag) != NULL ? NITF_SUCCESS : NITF_FAILURE); +} + + +NITFAPI(nitf_List*) nitf_TRE_find(nitf_TRE* tre, + const char* pattern, + nitf_Error* error) +{ + return tre->handler->find(tre, pattern, error); +} + + +NITFAPI(NITF_BOOL) nitf_TRE_setField(nitf_TRE * tre, + const char *tag, + NITF_DATA * data, + size_t dataLength, nitf_Error * error) +{ + return tre->handler->setField(tre, tag, data, dataLength, error); +} + +NITFAPI(nitf_Field*) nitf_TRE_getField(nitf_TRE* tre, const char* tag) +{ + return tre->handler->getField(tre, tag); +} + +NITFAPI(int) nitf_TRE_getCurrentSize(nitf_TRE* tre, nitf_Error* error) +{ + return tre->handler->getCurrentSize(tre, error); +} + +NITFAPI(const char*) nitf_TRE_getID(nitf_TRE* tre) +{ + return tre->handler->getID(tre); +} diff --git a/modules/c/nitf/source/TRECursor.c b/modules/c/nitf/source/TRECursor.c new file mode 100644 index 000000000..c3c673d18 --- /dev/null +++ b/modules/c/nitf/source/TRECursor.c @@ -0,0 +1,975 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/TRECursor.h" +#include "nitf/TREPrivateData.h" + + +#define TAG_BUF_LEN 256 + + + +NITFPRIV(nitf_Pair *) nitf_TRECursor_getTREPair(nitf_TRE * tre, + char *descTag, + char idx_str[10][10], + int looping, + nitf_Error * error); + +NITFPRIV(int) nitf_TRECursor_evalIf(nitf_TRE * tre, + nitf_TREDescription * desc_ptr, + char idx_str[10][10], + int looping, + nitf_Error * error); + +/** + * Helper function for evaluating loops + * Returns the number of loops that will be processed + */ +NITFPRIV(int) nitf_TRECursor_evalLoops(nitf_TRE * tre, + nitf_TREDescription * desc_ptr, + char idx_str[10][10], + int looping, + nitf_Error * error); + + +NITFPRIV(int) nitf_TRECursor_evalCondLength(nitf_TRE * tre, + nitf_TREDescription * desc_ptr, + char idx_str[10][10], + int looping, + nitf_Error * error); + + +/*! + * Evaluates the given postfix expression, looking up fields in the TRE, or + * using constant integers. + * + * \param tre The TRE to use + * \param idx The loop index/values + * \param looping The current loop level + * \param expression The postfix expression + * \param error The error to populate on failure + * \return NITF_SUCCESS on sucess or NITF_FAILURE otherwise + */ +NITFPRIV(int) nitf_TRECursor_evaluatePostfix(nitf_TRE *tre, + char idx[10][10], + int looping, + char *expression, + nitf_Error *error); + +typedef unsigned int (*NITF_TRE_CURSOR_COUNT_FUNCTION) (nitf_TRE *, + char idx[10][10], + int, + nitf_Error*); + + + +NITFAPI(nitf_TRECursor) nitf_TRECursor_begin(nitf_TRE * tre) +{ + nitf_Error error; + nitf_TRECursor tre_cursor; + nitf_TREDescription *dptr; + + tre_cursor.loop = nitf_IntStack_construct(&error); + tre_cursor.loop_idx = nitf_IntStack_construct(&error); + tre_cursor.loop_rtn = nitf_IntStack_construct(&error); + tre_cursor.numItems = 0; + tre_cursor.index = 0; + tre_cursor.looping = 0; + /* init the pointers */ + tre_cursor.end_ptr = NULL; + tre_cursor.prev_ptr = NULL; + tre_cursor.desc_ptr = NULL; + + if (tre) + { + /* set the start index */ + tre_cursor.index = -1; + /* count how many descriptions there are */ + dptr = ((nitf_TREPrivateData*)tre->priv)->description; + + while (dptr && (dptr->data_type != NITF_END)) + { + tre_cursor.numItems++; + dptr++; + } + tre_cursor.end_ptr = dptr; + memset(tre_cursor.tag_str, 0, TAG_BUF_LEN); + NITF_SNPRINTF(tre_cursor.tag_str, TAG_BUF_LEN, "%s", + ((nitf_TREPrivateData*)tre->priv)->description->tag); + tre_cursor.tre = tre; + } + + return tre_cursor; +} + +NITFAPI(nitf_TRECursor) nitf_TRECursor_clone(nitf_TRECursor *tre_cursor, + nitf_Error * error) +{ + nitf_TRECursor cursor; + cursor.numItems = tre_cursor->numItems; + cursor.index = tre_cursor->index; + cursor.looping = tre_cursor->looping; + cursor.loop = nitf_IntStack_clone(tre_cursor->loop, error); + cursor.loop_idx = nitf_IntStack_clone(tre_cursor->loop_idx, error); + cursor.loop_rtn = nitf_IntStack_clone(tre_cursor->loop_rtn, error); + cursor.tre = tre_cursor->tre; + cursor.end_ptr = tre_cursor->end_ptr; + + cursor.prev_ptr = tre_cursor->prev_ptr; + cursor.desc_ptr = tre_cursor->desc_ptr; + strcpy(cursor.tag_str, tre_cursor->tag_str); + cursor.length = tre_cursor->length; + return cursor; +} + + +/*! + * Normalizes the tag, which could be in a loop, and returns the nitf_Pair* from + * the TRE hash that corresponds to the current normalized tag. + */ +NITFPRIV(nitf_Pair *) nitf_TRECursor_getTREPair(nitf_TRE * tre, + char *descTag, + char idx_str[10][10], + int looping, nitf_Error * error) +{ + /* temp buf used for storing the qualified tag */ + char tag_str[TAG_BUF_LEN]; + + /* pointer for brace position */ + char *bracePtr; + + /* used as in iterator */ + int index = 0; + + /* temp used for looping */ + int i; + + /* the pair to return */ + nitf_Pair *pair = NULL; + + strncpy(tag_str, descTag, sizeof(tag_str)); + + /* deal with braces */ + if (strchr(descTag, '[')) + { + index = 0; + bracePtr = descTag; + /* split the string */ + *(strchr(tag_str, '[')) = 0; + bracePtr--; + while ((bracePtr = strchr(bracePtr + 1, '[')) != NULL) + { + /* tack on the depth */ + strcat(tag_str, idx_str[index++]); + } + } + else + { + /* it is dependent on something in another loop, + * so, we need to figure out what level. + * since tags are unique, we are ok checking like this + */ + pair = nitf_HashTable_find( + ((nitf_TREPrivateData*)tre->priv)->hash, tag_str); + for (i = 0; i < looping && !pair; ++i) + { + strcat(tag_str, idx_str[i]); + pair = nitf_HashTable_find( + ((nitf_TREPrivateData*)tre->priv)->hash, tag_str); + } + } + + /* pull the data from the hash about the dependent loop value */ + pair = nitf_HashTable_find(((nitf_TREPrivateData*)tre->priv)->hash, + tag_str); + return pair; +} + + + +NITFAPI(void) nitf_TRECursor_cleanup(nitf_TRECursor * tre_cursor) +{ + nitf_IntStack_destruct(&tre_cursor->loop); + nitf_IntStack_destruct(&tre_cursor->loop_idx); + nitf_IntStack_destruct(&tre_cursor->loop_rtn); +} + + +NITFAPI(NITF_BOOL) nitf_TRECursor_isDone(nitf_TRECursor * tre_cursor) +{ + nitf_Error error; + int isDone = (tre_cursor->desc_ptr == tre_cursor->end_ptr); + + /* check if the passed in cursor is not at the beginning */ + if (!isDone && tre_cursor->index >= 0) + { + nitf_TRECursor dolly = nitf_TRECursor_clone(tre_cursor, &error); + /* if iterate returns 0, we are done */ + isDone = !nitf_TRECursor_iterate(&dolly, &error); + isDone = isDone || (dolly.desc_ptr == dolly.end_ptr); + nitf_TRECursor_cleanup(&dolly); + } + return isDone; +} + +NITFAPI(int) nitf_TRECursor_iterate(nitf_TRECursor * tre_cursor, + nitf_Error * error) +{ + nitf_TREDescription *dptr; + + int *stack; /* used for in conjuction with the stacks */ + int index; /* used for in conjuction with the stacks */ + + int loopCount = 0; /* tells how many times to loop */ + int loop_rtni = 0; /* used for temp storage */ + int loop_idxi = 0; /* used for temp storage */ + + int numIfs = 0; /* used to keep track of nested Ifs */ + int numLoops = 0; /* used to keep track of nested Loops */ + int done = 0; /* flag used for special cases */ + + char idx_str[10][10]; /* used for keeping track of indexes */ + + if (!tre_cursor->loop || !tre_cursor->loop_idx + || !tre_cursor->loop_rtn) + { + /* not initialized */ + nitf_Error_init(error, "Unhandled TRE Value data type", + NITF_CTXT, NITF_ERR_INVALID_PARAMETER); + return NITF_FAILURE; + } + + /* count how many descriptions there are */ + + dptr = ((nitf_TREPrivateData*)tre_cursor->tre->priv)->description; + + while (!done) + { + done = 1; /* set the flag */ + + /* iterate the index */ + tre_cursor->index++; + + if (tre_cursor->index < tre_cursor->numItems) + { + memset(tre_cursor->tag_str, 0, TAG_BUF_LEN); + + tre_cursor->prev_ptr = tre_cursor->desc_ptr; + tre_cursor->desc_ptr = &dptr[tre_cursor->index]; + + /* if already in a loop, prepare the array of values */ + if (tre_cursor->looping) + { + stack = tre_cursor->loop_idx->st; + /* assert, because we only prepare for 10 */ + assert(tre_cursor->looping <= 10); + + for (index = 0; index < tre_cursor->looping; index++) + { + NITF_SNPRINTF(idx_str[index], TAG_BUF_LEN, + "[%d]", stack[index]); + } + } + + /* check if it is an actual item now */ + /* ASCII string */ + if ((tre_cursor->desc_ptr->data_type == NITF_BCS_A) || + /* ASCII number */ + (tre_cursor->desc_ptr->data_type == NITF_BCS_N) || + /* raw bytes */ + (tre_cursor->desc_ptr->data_type == NITF_BINARY)) + { + NITF_SNPRINTF(tre_cursor->tag_str, TAG_BUF_LEN, "%s", + tre_cursor->desc_ptr->tag); + /* check if data is part of an array */ + if (tre_cursor->looping) + { + stack = tre_cursor->loop_idx->st; + for (index = 0; index < tre_cursor->looping; index++) + { + char entry[64]; + NITF_SNPRINTF(entry, 64, "[%d]", stack[index]); + strcat(tre_cursor->tag_str, entry); + } + } + + /* check to see if we don't know the length */ + if (tre_cursor->desc_ptr->data_count == + NITF_TRE_CONDITIONAL_LENGTH) + { + /* compute it from the function given */ + if (tre_cursor->desc_ptr->special) + { + /* evaluate the special string as a postfix expression */ + tre_cursor->length = + nitf_TRECursor_evaluatePostfix( + tre_cursor->tre, + idx_str, + tre_cursor->looping, + tre_cursor->desc_ptr->special, + error); + + if (tre_cursor->length < 0) + { + /* error! */ + nitf_Error_print(error, stderr, "TRE expression error:"); + return NITF_FAILURE; + } + } + else + { + /* should we return failure here? */ + /* for now, just set the length to 0, which forces an + iteration... */ + tre_cursor->length = 0; + } + + if (tre_cursor->length == 0) + { + return nitf_TRECursor_iterate(tre_cursor, error); + } + } + else + { + /* just set the length that was in the TREDescription */ + tre_cursor->length = tre_cursor->desc_ptr->data_count; + } + } + /* NITF_LOOP, NITF_IF, etc. */ + else if ((tre_cursor->desc_ptr->data_type >= + NITF_LOOP) + && (tre_cursor->desc_ptr->data_type < NITF_END)) + { + done = 0; /* set the flag */ + + /* start of a loop */ + if (tre_cursor->desc_ptr->data_type == NITF_LOOP) + { + loopCount = + nitf_TRECursor_evalLoops(tre_cursor->tre, + tre_cursor->desc_ptr, idx_str, + tre_cursor->looping, error); + if (loopCount > 0) + { + tre_cursor->looping++; + /* record loopcount in @loop stack */ + nitf_IntStack_push(tre_cursor->loop, loopCount, + error); + /* record i in @loop_rtn stack */ + nitf_IntStack_push(tre_cursor->loop_rtn, + tre_cursor->index, error); + /* record a 0 in @loop_idx stack */ + nitf_IntStack_push(tre_cursor->loop_idx, 0, error); + } + else + { + numLoops = 1; + /* skip until we see the matching ENDLOOP */ + while (numLoops + && (++tre_cursor->index < + tre_cursor->numItems)) + { + tre_cursor->desc_ptr = + &dptr[tre_cursor->index]; + if (tre_cursor->desc_ptr->data_type == + NITF_LOOP) + numLoops++; + else if (tre_cursor->desc_ptr->data_type == + NITF_ENDLOOP) + numLoops--; + } + } + } + /* end of a loop */ + else if (tre_cursor->desc_ptr->data_type == NITF_ENDLOOP) + { + /* retrieve loopcount from @loop stack */ + loopCount = nitf_IntStack_pop(tre_cursor->loop, error); + /* retrieve loop_rtn from @loop_rtn stack */ + loop_rtni = + nitf_IntStack_pop(tre_cursor->loop_rtn, error); + /* retrieve loop_idx from @loop_idx stack */ + loop_idxi = + nitf_IntStack_pop(tre_cursor->loop_idx, error); + + if (--loopCount > 0) + { + /* record loopcount in @loop stack */ + nitf_IntStack_push(tre_cursor->loop, loopCount, + error); + /* record i in @loop_rtn stack */ + nitf_IntStack_push(tre_cursor->loop_rtn, loop_rtni, + error); + /* record idx in @loop_idx stack */ + nitf_IntStack_push(tre_cursor->loop_idx, + ++loop_idxi, error); + /* jump to the start of the loop */ + tre_cursor->index = loop_rtni; + } + else + { + --tre_cursor->looping; + } + } + /* an if clause */ + else if (tre_cursor->desc_ptr->data_type == NITF_IF) + { + if (!nitf_TRECursor_evalIf + (tre_cursor->tre, + tre_cursor->desc_ptr, + idx_str, + tre_cursor->looping, error)) + { + numIfs = 1; + /* skip until we see the matching ENDIF */ + while (numIfs + && (++tre_cursor->index < + tre_cursor->numItems)) + { + tre_cursor->desc_ptr = + &dptr[tre_cursor->index]; + if (tre_cursor->desc_ptr->data_type == NITF_IF) + numIfs++; + else if (tre_cursor->desc_ptr->data_type == + NITF_ENDIF) + numIfs--; + } + } + } + } + else + { + nitf_Error_init(error, "Unhandled TRE Value data type", + NITF_CTXT, NITF_ERR_INVALID_PARAMETER); + return NITF_FAILURE; + } + } + else + { + /* should return FALSE instead. signifies we are DONE iterating! */ + return NITF_FAILURE; + } + } + return NITF_SUCCESS; +} + + +/** + * Helper function for evaluating loops + * Returns the number of loops that will be processed + */ +NITFPRIV(int) nitf_TRECursor_evalLoops(nitf_TRE* tre, + nitf_TREDescription* desc_ptr, + char idx_str[10][10], + int looping, nitf_Error* error) +{ + int loops; + + /* temp buf used for manipulating the loop label */ + char str[TAG_BUF_LEN]; + + nitf_Pair *pair; + nitf_Field *field; + + char *op; + char *valPtr; + + /* used for the possible data in the loop label */ + int loopVal; + + /* if the user wants a constant value */ + if (desc_ptr->label && strcmp(desc_ptr->label, NITF_CONST_N) == 0) + { + loops = NITF_ATO32(desc_ptr->tag); + } + + else if (desc_ptr->label && strcmp(desc_ptr->label, NITF_FUNCTION) == 0) + { + NITF_TRE_CURSOR_COUNT_FUNCTION fn = + (NITF_TRE_CURSOR_COUNT_FUNCTION)desc_ptr->tag; + + + loops = (*fn)(tre, idx_str, looping, error); + + if (loops == -1) + return NITF_FAILURE; + } + + else + { + pair = nitf_TRECursor_getTREPair(tre, desc_ptr->tag, + idx_str, looping, error); + if (!pair) + { + nitf_Error_init(error, + "nitf_TRECursor_evalLoops: invalid TRE loop counter", + NITF_CTXT, NITF_ERR_INVALID_PARAMETER); + return NITF_FAILURE; + } + field = (nitf_Field *) pair->data; + + /* get the int value */ + if (!nitf_Field_get + (field, (char *) &loops, NITF_CONV_INT, sizeof(loops), error)) + { + return NITF_FAILURE; + } + + /* if the label is not empty, then apply some functionality */ + if (desc_ptr->label && strlen(desc_ptr->label) != 0) + { + assert(strlen(desc_ptr->label) < sizeof(str)); + + strcpy(str, desc_ptr->label); + op = str; + while (isspace(*op)) + op++; + + if ((*op == '+') || + (*op == '-') || + (*op == '*') || (*op == '/') || (*op == '%')) + { + valPtr = op + 1; + while (isspace(*valPtr)) + valPtr++; + + loopVal = NITF_ATO32(valPtr); + + switch (*op) + { + case '+': + loops += loopVal; + break; + case '-': + loops -= loopVal; + break; + case '*': + loops *= loopVal; + break; + case '/': + /* check for divide by zero */ + if (loopVal == 0) + { + nitf_Error_init(error, + "nitf_TRECursor_evalLoops: attempt to divide by zero", + NITF_CTXT, + NITF_ERR_INVALID_PARAMETER); + return NITF_FAILURE; + } + loops /= loopVal; + break; + case '%': + loops %= loopVal; + break; + default: + break; + } + } + else + { + nitf_Error_init(error, "nitf_TRECursor_evalLoops: invalid operator", + NITF_CTXT, NITF_ERR_INVALID_PARAMETER); + return NITF_FAILURE; + } + } + } + return loops < 0 ? 0 : loops; +} + + +NITFPRIV(int) nitf_TRECursor_evalIf(nitf_TRE* tre, + nitf_TREDescription* desc_ptr, + char idx_str[10][10], + int looping, + nitf_Error* error) +{ + nitf_Field *field; + nitf_Pair *pair; + + /* temp buf for the label */ + char str[TAG_BUF_LEN]; + char *emptyPtr; + char *op; + char *valPtr; + + /* the return status */ + int status = 0; + + /* used as the value for comparing */ + int fieldData; + + /* the value defined int the TRE descrip */ + int treData; + + /* the bit-field for comparing */ + unsigned int bitFieldData; + + /* the bit-field defined in the TRE descrip */ + unsigned int treBitField; + + /* get the data out of the hashtable */ + pair = nitf_TRECursor_getTREPair(tre, desc_ptr->tag, idx_str, + looping, error); + if (!pair) + { + nitf_Error_init(error, "Unable to find tag in TRE hash", + NITF_CTXT, NITF_ERR_UNK); + return NITF_FAILURE; + } + field = (nitf_Field *) pair->data; + assert(strlen(desc_ptr->label) < sizeof(str)); + + strcpy(str, desc_ptr->label); + op = str; + + while (isspace(*op)) + op++; + + /* split the string at the space */ + emptyPtr = strchr(op, ' '); + *emptyPtr = 0; + + /* remember where the operand is */ + valPtr = emptyPtr + 1; + + /* check if it is a string comparison of either 'eq' or 'ne' */ + if ((strcmp(op, "eq") == 0) || (strcmp(op, "ne") == 0)) + { + /* must be a string */ + if (field->type == NITF_BCS_N) + { + nitf_Error_init(error, + "evaluate: can't use eq/ne to compare a number", + NITF_CTXT, NITF_ERR_INVALID_PARAMETER); + return NITF_FAILURE; + } + status = strncmp(field->raw, valPtr, field->length); + status = strcmp(op, "eq") == 0 ? !status : status; + } + /* check if it is a logical operator for ints */ + else if ((strcmp(op, "<") == 0) || + (strcmp(op, ">") == 0) || + (strcmp(op, ">=") == 0) || + (strcmp(op, "<=") == 0) || + (strcmp(op, "==") == 0) || (strcmp(op, "!=") == 0)) + { + /* make sure it is a number */ + if (field->type != NITF_BCS_N) + { + nitf_Error_init(error, + "evaluate: can't use strings for logical expressions", + NITF_CTXT, NITF_ERR_INVALID_PARAMETER); + return NITF_FAILURE; + } + + treData = NITF_ATO32(valPtr); + if (!nitf_Field_get + (field, (char *) &fieldData, NITF_CONV_INT, sizeof(fieldData), + error)) + { + return NITF_FAILURE; + } + + /* 0 -> equal, <0 -> less true, >0 greater true */ + status = fieldData - treData; + + if (strcmp(op, ">") == 0) + status = (status > 0); + else if (strcmp(op, "<") == 0) + status = (status < 0); + else if (strcmp(op, ">=") == 0) + status = (status >= 0); + else if (strcmp(op, "<=") == 0) + status = (status <= 0); + else if (strcmp(op, "==") == 0) + status = (status == 0); + else if (strcmp(op, "!=") == 0) + status = (status != 0); + } + /* check if it is a bit-wise operator */ + else if (strcmp(op, "&") == 0) + { + /* make sure it is a binary field */ + if (field->type != NITF_BINARY) + { + nitf_Error_init(error, + "evaluate: must use binary data for bit-wise expressions", + NITF_CTXT, + NITF_ERR_INVALID_PARAMETER); + return NITF_FAILURE; + } + + treBitField = NITF_ATOU32_BASE(valPtr, 0); + if (!nitf_Field_get(field, + (char *)&bitFieldData, + NITF_CONV_UINT, + sizeof(bitFieldData), + error)) + { + return NITF_FAILURE; + } + + /* check this bit field */ + status = ((treBitField & bitFieldData) != 0); + } + /* otherwise, they used a bad operator */ + else + { + nitf_Error_init(error, "evaluate: invalid comparison operator", + NITF_CTXT, NITF_ERR_INVALID_PARAMETER); + return NITF_FAILURE; + } + return status; +} + + + +/** + * Helper function for evaluating loops + * Returns the number of loops that will be processed + */ +NITFPRIV(int) nitf_TRECursor_evalCondLength(nitf_TRE* tre, + nitf_TREDescription* desc_ptr, + char idx_str[10][10], + int looping, + nitf_Error* error) +{ + int computedLength; + /* temp buf used for manipulating the loop label */ + char str[TAG_BUF_LEN]; + nitf_Pair *pair; + nitf_Field *field; + + char *op; + char *valPtr; + + /* used for the possible data in the description label */ + int funcVal; + + pair = nitf_TRECursor_getTREPair(tre, desc_ptr->tag, + idx_str, looping, error); + if (!pair) + { + nitf_Error_init(error, + "nitf_TRECursor_evalCondLength: invalid TRE reference", + NITF_CTXT, NITF_ERR_INVALID_PARAMETER); + return NITF_FAILURE; + } + field = (nitf_Field *) pair->data; + + /* get the int value */ + if (!nitf_Field_get + (field, (char *) &computedLength, NITF_CONV_INT, + sizeof(computedLength), error)) + { + return NITF_FAILURE; + } + + /* if the label is not empty, then apply some functionality */ + if (desc_ptr->label && strlen(desc_ptr->label) != 0) + { + assert(strlen(desc_ptr->label) < sizeof(str)); + + strcpy(str, desc_ptr->label); + op = str; + while (isspace(*op)) + op++; + if ((*op == '+') || + (*op == '-') || (*op == '*') || (*op == '/') || (*op == '%')) + { + valPtr = op + 1; + while (isspace(*valPtr)) + valPtr++; + + funcVal = NITF_ATO32(valPtr); + + switch (*op) + { + case '+': + computedLength += funcVal; + break; + case '-': + computedLength -= funcVal; + break; + case '*': + computedLength *= funcVal; + break; + case '/': + /* check for divide by zero */ + if (funcVal == 0) + { + nitf_Error_init(error, + "nitf_TRECursor_evalCondLength: attempt to divide by zero", + NITF_CTXT, NITF_ERR_INVALID_PARAMETER); + return NITF_FAILURE; + } + computedLength /= funcVal; + break; + case '%': + computedLength %= funcVal; + break; + default: + break; + } + } + else + { + nitf_Error_init(error, + "nitf_TRECursor_evalCondLength: invalid operator", + NITF_CTXT, NITF_ERR_INVALID_PARAMETER); + return NITF_FAILURE; + } + } + return computedLength < 0 ? 0 : computedLength; +} + +NITFPRIV(int) nitf_TRECursor_evaluatePostfix(nitf_TRE *tre, + char idx[10][10], + int looping, + char *expression, + nitf_Error *error) +{ + nitf_List *parts = NULL; + nitf_IntStack *stack = NULL; + int expressionValue; + + /* create the postfix stack */ + stack = nitf_IntStack_construct(error); + if (!stack) + goto CATCH_ERROR; + + /* split the expression by spaces */ + parts = nitf_Utils_splitString(expression, 0, error); + if (!parts) + goto CATCH_ERROR; + + while(!nitf_List_isEmpty(parts)) + { + char* expr = (char*) nitf_List_popFront(parts); + if (strlen(expr) == 1 && + (expr[0] == '+' || expr[0] == '-' || expr[0] == '*' || + expr[0] == '/' || expr[0] == '%')) + { + int op1, op2, stackSize; + stackSize = nitf_IntStack_depth(stack, error) + 1; + + if (stackSize == 0) + { + /* error for postfix... */ + nitf_Error_init(error, + "nitf_TRECursor_evaluatePostfix: invalid expression", + NITF_CTXT, NITF_ERR_INVALID_PARAMETER); + goto CATCH_ERROR; + } + + op2 = nitf_IntStack_pop(stack, error); + if (stackSize == 1) + op1 = 0; /* assume 0 for the first operand of a unary op */ + else + op1 = nitf_IntStack_pop(stack, error); + + switch(expr[0]) + { + case '+': + nitf_IntStack_push(stack, (op1 + op2), error); + break; + case '-': + nitf_IntStack_push(stack, (op1 - op2), error); + break; + case '*': + nitf_IntStack_push(stack, (op1 * op2), error); + break; + case '/': + /* check for divide by zero */ + if (op2 == 0) + { + nitf_Error_init(error, + "nitf_TRECursor_evaluatePostfix: attempt to divide by zero", + NITF_CTXT, NITF_ERR_INVALID_PARAMETER); + goto CATCH_ERROR; + } + nitf_IntStack_push(stack, (op1 / op2), error); + break; + case '%': + nitf_IntStack_push(stack, (op1 % op2), error); + break; + } + } + else + { + /* evaluate as an integer and push onto the stack */ + if (nitf_Utils_isNumeric(expr)) + { + nitf_IntStack_push(stack, NITF_ATO32(expr), error); + } + else + { + /* must be a dependent field */ + int intVal; + nitf_Field *field = NULL; + nitf_Pair *pair = nitf_TRECursor_getTREPair(tre, expr, idx, + looping, error); + + if (!pair) + { + nitf_Error_init(error, + "nitf_TRECursor_evaluatePostfix: invalid TRE field reference", + NITF_CTXT, NITF_ERR_INVALID_PARAMETER); + goto CATCH_ERROR; + } + field = (nitf_Field *) pair->data; + + /* get the int value */ + if (!nitf_Field_get(field, (char*) &intVal, NITF_CONV_INT, + sizeof(intVal), error)) + { + goto CATCH_ERROR; + } + nitf_IntStack_push(stack, intVal, error); + } + } + + /* must cleanup after ourselves */ + if (expr) + NITF_FREE(expr); + } + + /* if all is well, the postfix stack should have one value */ + if (nitf_IntStack_depth(stack, error) != 0) + { + nitf_Error_init(error, "Invalid postfix expression", + NITF_CTXT, NITF_ERR_INVALID_PARAMETER); + goto CATCH_ERROR; + } + + expressionValue = nitf_IntStack_pop(stack, error); + + nitf_IntStack_destruct(&stack); + nitf_List_destruct(&parts); + + return expressionValue; + + CATCH_ERROR: + if (stack) nitf_IntStack_destruct(&stack); + if (parts) nitf_List_destruct(&parts); + return -1; +} diff --git a/modules/c/nitf/source/TREPrivateData.c b/modules/c/nitf/source/TREPrivateData.c new file mode 100644 index 000000000..49fdf08da --- /dev/null +++ b/modules/c/nitf/source/TREPrivateData.c @@ -0,0 +1,237 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/TREPrivateData.h" + + +NITFAPI(nitf_TREPrivateData *) nitf_TREPrivateData_construct( + nitf_Error * error) +{ + nitf_TREPrivateData *priv = (nitf_TREPrivateData*) NITF_MALLOC( + sizeof(nitf_TREPrivateData)); + if (!priv) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + return NULL; + } + + priv->length = 0; + priv->descriptionName = NULL; + priv->description = NULL; + priv->userData = NULL; + + /* create the hashtable for the fields */ + priv->hash = nitf_HashTable_construct(NITF_TRE_HASH_SIZE, error); + + if (!priv->hash) + { + nitf_TREPrivateData_destruct(&priv); + return NULL; + } + + /* ??? change policy? */ + nitf_HashTable_setPolicy(priv->hash, NITF_DATA_ADOPT); + + return priv; +} + + +NITFAPI(nitf_TREPrivateData *) +nitf_TREPrivateData_clone(nitf_TREPrivateData *source, nitf_Error * error) +{ + nitf_TREPrivateData *priv = NULL; + + /* temporary nitf_List pointer */ + nitf_List *lPtr; + + /* temporary nitf_Field pointer */ + nitf_Field *field; + + /* temporary nitf_Pair pointer */ + nitf_Pair *pair; + + /* iterator to front of list */ + nitf_ListIterator iter; + + /* iterator to back of list */ + nitf_ListIterator end; + + /* used for iterating */ + int i; + + if (source) + { + priv = nitf_TREPrivateData_construct(error); + if (!priv) + goto CATCH_ERROR; + + if (!nitf_TREPrivateData_setDescriptionName( + priv, source->descriptionName, error)) + { + goto CATCH_ERROR; + } + + /* Copy the entire contents of the hash */ + for (i = 0; i < source->hash->nbuckets; i++) + { + /* Foreach chain in the hash table... */ + lPtr = source->hash->buckets[i]; + iter = nitf_List_begin(lPtr); + end = nitf_List_end(lPtr); + + /* And while they are different... */ + while (nitf_ListIterator_notEqualTo(&iter, &end)) + { + /* Retrieve the field at the iterator... */ + pair = (nitf_Pair *) nitf_ListIterator_get(&iter); + + /* Cast it back to a field... */ + field = (nitf_Field *) pair->data; + + /* clone the field */ + field = nitf_Field_clone(field, error); + + /* If that failed, we need to destruct */ + if (!field) + goto CATCH_ERROR; + + /* Yes, now we can insert the new field! */ + if (!nitf_HashTable_insert(priv->hash, + pair->key, field, error)) + { + goto CATCH_ERROR; + } + nitf_ListIterator_increment(&iter); + } + } + } + else + { + nitf_Error_initf(error, + NITF_CTXT, + NITF_ERR_INVALID_OBJECT, + "Trying to clone NULL pointer"); + } + return priv; + + CATCH_ERROR: + if (priv) + nitf_TREPrivateData_destruct(&priv); + return NULL; +} + + +/** + * Helper function for destructing the HashTable pairs + */ +NITFPRIV(int) destructHashValue(nitf_HashTable * ht, + nitf_Pair * pair, + NITF_DATA* userData, + nitf_Error * error) +{ + if (pair) + if (pair->data) + nitf_Field_destruct((nitf_Field **) & pair->data); + return NITF_SUCCESS; +} + + +NITFAPI(void) nitf_TREPrivateData_destruct(nitf_TREPrivateData **priv) +{ + nitf_Error e; + if (*priv) + { + if ((*priv)->descriptionName) + { + NITF_FREE((*priv)->descriptionName); + (*priv)->descriptionName = NULL; + } + if ((*priv)->hash) + { + /* destruct each field in the hash */ + nitf_HashTable_foreach((*priv)->hash, + (NITF_HASH_FUNCTOR) destructHashValue, + NULL, &e); + /* destruct the hash */ + nitf_HashTable_destruct(&((*priv)->hash)); + + } + NITF_FREE(*priv); + *priv = NULL; + } +} + + +NITFPROT(NITF_BOOL) nitf_TREPrivateData_flush(nitf_TREPrivateData *priv, + nitf_Error * error) +{ + if (priv && priv->hash) + { + /* destruct each field in the hash */ + nitf_HashTable_foreach(priv->hash, + (NITF_HASH_FUNCTOR) destructHashValue, + NULL, error); + /* destruct the hash */ + nitf_HashTable_destruct(&(priv->hash)); + + } + + /* create the hashtable for the fields */ + priv->hash = nitf_HashTable_construct(NITF_TRE_HASH_SIZE, error); + + if (!priv->hash) + { + nitf_TREPrivateData_destruct(&priv); + return NITF_FAILURE; + } + + nitf_HashTable_setPolicy(priv->hash, NITF_DATA_ADOPT); + + return NITF_SUCCESS; +} + + +NITFPROT(NITF_BOOL) nitf_TREPrivateData_setDescriptionName( + nitf_TREPrivateData *priv, const char* name, nitf_Error * error) +{ + /* if already set, free it */ + if (priv->descriptionName) + { + NITF_FREE(priv->descriptionName); + priv->descriptionName = NULL; + } + + /* copy the description id */ + if (name) + { + priv->descriptionName = (char*)NITF_MALLOC(strlen(name) + 1); + if (!priv->descriptionName) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + return NITF_FAILURE; + } + strcpy(priv->descriptionName, name); + } + return NITF_SUCCESS; +} diff --git a/modules/c/nitf/source/TREUtils.c b/modules/c/nitf/source/TREUtils.c new file mode 100644 index 000000000..b0cfc4a55 --- /dev/null +++ b/modules/c/nitf/source/TREUtils.c @@ -0,0 +1,1062 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/TREUtils.h" +#include "nitf/TREPrivateData.h" + + +NITFAPI(int) nitf_TREUtils_parse(nitf_TRE * tre, + char *bufptr, + nitf_Error * error) +{ + int status = 1; + int iterStatus = NITF_SUCCESS; + int offset = 0; + int length; + nitf_TRECursor cursor; + nitf_Field *field = NULL; + nitf_TREPrivateData *privData = NULL; + + /* get out if TRE is null */ + if (!tre) + { + nitf_Error_init(error, "parse -> invalid tre object", + NITF_CTXT, NITF_ERR_INVALID_PARAMETER); + return NITF_FAILURE; + } + + privData = (nitf_TREPrivateData*)tre->priv; + + /* flush the hash first, to protect from duplicate entries */ + if (privData) + { + nitf_TREPrivateData_flush(privData, error); + } + + cursor = nitf_TRECursor_begin(tre); + while (offset < privData->length && status) + { + if ((iterStatus = + nitf_TRECursor_iterate(&cursor, error)) == NITF_SUCCESS) + { + length = cursor.length; + if (length == NITF_TRE_GOBBLE) + { + length = privData->length - offset; + } + + /* no need to call setValue, because we already know + * it is OK for this one to be in the hash + */ + + /* construct the field */ + field = nitf_Field_construct(length, + cursor.desc_ptr->data_type, error); + if (!field) + goto CATCH_ERROR; + + /* first, check to see if we need to swap bytes */ + if (field->type == NITF_BINARY + && (length == NITF_INT16_SZ || length == NITF_INT32_SZ)) + { + if (length == NITF_INT16_SZ) + { + nitf_Int16 int16 = + (nitf_Int16)NITF_NTOHS(*((nitf_Int16 *) (bufptr + offset))); + status = nitf_Field_setRawData(field, + (NITF_DATA *) & int16, length, error); + } + else if (length == NITF_INT32_SZ) + { + nitf_Int32 int32 = + (nitf_Int32)NITF_NTOHL(*((nitf_Int32 *) (bufptr + offset))); + status = nitf_Field_setRawData(field, + (NITF_DATA *) & int32, length, error); + } + } + else + { + /* check for the other binary lengths ... */ + if (field->type == NITF_BINARY) + { + /* TODO what to do??? 8 bit is ok, but what about 64? */ + /* for now, just let it go through... */ + } + + /* now, set the data */ + status = nitf_Field_setRawData(field, (NITF_DATA *) (bufptr + offset), + length, error); + } + +#ifdef NITF_DEBUG + { + fprintf(stdout, "Adding Field [%s] to TRE [%s]\n", + cursor.tag_str, tre->tag); + } +#endif + + /* add to the hash */ + nitf_HashTable_insert(((nitf_TREPrivateData*)tre->priv)->hash, + cursor.tag_str, field, error); + + offset += length; + } + /* otherwise, the iterate function thinks we are done */ + else + { + break; + } + } + nitf_TRECursor_cleanup(&cursor); + + /* check if we still have more to parse, and throw an error if so */ + if (offset < privData->length) + { + nitf_Error_init(error, "TRE data is longer than it should be", + NITF_CTXT, NITF_ERR_INVALID_OBJECT); + status = NITF_FAILURE; + } + return status; + + /* deal with errors here */ + CATCH_ERROR: + return NITF_FAILURE; +} + +NITFAPI(char *) nitf_TREUtils_getRawData(nitf_TRE * tre, nitf_Uint32* treLength, nitf_Error * error) +{ + int status = 1; + int offset = 0; + nitf_Uint32 length; + int tempLength; + + /* data buffer - Caller must free this */ + char *data = NULL; + + /* temp data buffer */ + char *tempBuf = NULL; + + /* temp nitf_Pair */ + nitf_Pair *pair; + + /* temp nitf_Field */ + nitf_Field *field; + + /* the cursor */ + nitf_TRECursor cursor; + + /* get actual length of TRE */ + length = nitf_TREUtils_computeLength(tre); + *treLength = length; + + if (length <= 0) + { + nitf_Error_init(error, "TRE has invalid length", + NITF_CTXT, NITF_ERR_INVALID_OBJECT); + return NULL; + } + + /* allocate the memory - this does not get freed in this function */ + data = (char *) NITF_MALLOC(length + 1); + if (!data) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + goto CATCH_ERROR; + } + memset(data, 0, length + 1); + + cursor = nitf_TRECursor_begin(tre); + while (!nitf_TRECursor_isDone(&cursor) && status && offset < length) + { + if (nitf_TRECursor_iterate(&cursor, error) == NITF_SUCCESS) + { + pair = nitf_HashTable_find(((nitf_TREPrivateData*)tre->priv)->hash, + cursor.tag_str); + if (pair && pair->data) + { + tempLength = cursor.length; + if (tempLength == NITF_TRE_GOBBLE) + { + tempLength = length - offset; + } + field = (nitf_Field *) pair->data; + + /* get the raw data */ + tempBuf = NITF_MALLOC(tempLength); + if (!tempBuf) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + goto CATCH_ERROR; + } + /* get the data as raw buf */ + nitf_Field_get(field, (NITF_DATA *) tempBuf, + NITF_CONV_RAW, tempLength, error); + + /* first, check to see if we need to swap bytes */ + if (field->type == NITF_BINARY) + { + if (tempLength == NITF_INT16_SZ) + { + nitf_Int16 int16 = + (nitf_Int16)NITF_HTONS(*((nitf_Int16 *) tempBuf)); + memcpy(tempBuf, (char*)&int16, tempLength); + } + else if (tempLength == NITF_INT32_SZ) + { + nitf_Int32 int32 = + (nitf_Int32)NITF_HTONL(*((nitf_Int32 *) tempBuf)); + memcpy(tempBuf, (char*)&int32, tempLength); + } + else + { + /* TODO what to do??? 8 bit is ok, but what about 64? */ + /* for now, just let it go through... */ + } + } + + /* now, memcpy the data */ + memcpy(data + offset, tempBuf, tempLength); + offset += tempLength; + + /* free the buf */ + NITF_FREE(tempBuf); + } + else + { + nitf_Error_init(error, + "Failed due to missing TRE field(s)", + NITF_CTXT, NITF_ERR_INVALID_OBJECT); + goto CATCH_ERROR; + } + } + } + nitf_TRECursor_cleanup(&cursor); + return data; + + /* deal with errors here */ + CATCH_ERROR: + if (data) + NITF_FREE(data); + return NULL; +} + +NITFAPI(NITF_BOOL) nitf_TREUtils_readField(nitf_IOInterface* io, + char *field, + int length, nitf_Error * error) +{ + NITF_BOOL status; + + /* Make sure the field is nulled out */ + memset(field, 0, length); + + /* Read from the IO handle */ + status = nitf_IOInterface_read(io, field, length, error); + if (!status) + { + nitf_Error_init(error, + "Unable to read from IO object", + NITF_CTXT, NITF_ERR_READING_FROM_FILE); + } + return status; +} + +NITFAPI(NITF_BOOL) nitf_TREUtils_setValue(nitf_TRE * tre, + const char *tag, + NITF_DATA * data, + size_t dataLength, + nitf_Error * error) +{ + nitf_Pair *pair; + nitf_Field *field = NULL; + nitf_TRECursor cursor; + NITF_BOOL done = 0; + NITF_BOOL status = 1; + nitf_FieldType type = NITF_BCS_A; + + /* used temporarily for storing the length */ + int length; + + /* get out if TRE is null */ + if (!tre) + { + nitf_Error_init(error, "setValue -> invalid tre object", + NITF_CTXT, NITF_ERR_INVALID_PARAMETER); + return NITF_FAILURE; + } + + /* If the field already exists, get it and modify it */ + if (nitf_HashTable_exists(((nitf_TREPrivateData*)tre->priv)->hash, tag)) + { + pair = nitf_HashTable_find( + ((nitf_TREPrivateData*)tre->priv)->hash, tag); + field = (nitf_Field *) pair->data; + + if (!field) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_INVALID_PARAMETER, + "setValue -> invalid field object: %s", tag); + return NITF_FAILURE; + } + + /* check to see if the data passed in is too large or too small */ + if ((dataLength > field->length && !field->resizable) || dataLength < 1) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_INVALID_PARAMETER, + "setValue -> invalid dataLength for field: %s", tag); + return NITF_FAILURE; + } + + if (!nitf_Field_setRawData + (field, (NITF_DATA *) data, dataLength, error)) + { + return NITF_FAILURE; + } +#ifdef NITF_DEBUG + fprintf(stdout, "Setting (and filling) Field [%s] to TRE [%s]\n", + tag, tre->tag); +#endif + + /* Now we need to fill our data */ + if (!nitf_TREUtils_fillData(tre, + ((nitf_TREPrivateData*)tre->priv)->description, + error)) + return NITF_FAILURE; + + } + /* it doesn't exist in the hash yet, so we need to find it */ + else + { + + cursor = nitf_TRECursor_begin(tre); + while (!nitf_TRECursor_isDone(&cursor) && !done && status) + { + if (nitf_TRECursor_iterate(&cursor, error) == NITF_SUCCESS) + { + /* we found it */ + if (strcmp(tag, cursor.tag_str) == 0) + { + if (cursor.desc_ptr->data_type == NITF_BCS_A) + { + type = NITF_BCS_A; + } + else if (cursor.desc_ptr->data_type == NITF_BCS_N) + { + type = NITF_BCS_N; + } + else if (cursor.desc_ptr->data_type == NITF_BINARY) + { + type = NITF_BINARY; + } + else + { + /* bad type */ + nitf_Error_init(error, + "setValue -> invalid data type", + NITF_CTXT, + NITF_ERR_INVALID_PARAMETER); + return NITF_FAILURE; + } + + length = cursor.length; + /* check to see if we should gobble the rest */ + if (length == NITF_TRE_GOBBLE) + { + length = dataLength; + } + + /* construct the field */ + field = nitf_Field_construct(length, type, error); + + /* now, set the data */ + nitf_Field_setRawData(field, (NITF_DATA *) data, + dataLength, error); + +#ifdef NITF_DEBUG + fprintf(stdout, "Adding (and filling) Field [%s] to TRE [%s]\n", + cursor.tag_str, tre->tag); +#endif + + /* add to the hash */ + nitf_HashTable_insert( + ((nitf_TREPrivateData*)tre->priv)->hash, + cursor.tag_str, field, error); + + + /* Now we need to fill our data */ + if (!nitf_TREUtils_fillData(tre, ((nitf_TREPrivateData*)tre->priv)->description, error)) + return NITF_FAILURE; + + done = 1; /* set, so we break out of loop */ + } + } + } + /* did we find it? */ + if (!done) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_UNK, + "Unable to find tag, '%s', in TRE hash for TRE '%s'", + tag, tre->tag); + status = 0; + } + nitf_TRECursor_cleanup(&cursor); + } + return status; + +} + +NITFAPI(NITF_BOOL) +nitf_TREUtils_setDescription(nitf_TRE* tre, + nitf_Uint32 length, + nitf_Error* error) +{ + + nitf_TREDescriptionSet *descriptions = NULL; + nitf_TREDescriptionInfo *infoPtr = NULL; + int numDescriptions = 0; + + if (!tre) + { + nitf_Error_init(error, "setDescription -> invalid tre object", + NITF_CTXT, NITF_ERR_INVALID_PARAMETER); + return NITF_FAILURE; + } + descriptions = (nitf_TREDescriptionSet*)tre->handler->data; + + if (!descriptions) + { + nitf_Error_init(error, "TRE Description Set is NULL", + NITF_CTXT, NITF_ERR_INVALID_OBJECT); + return NITF_FAILURE; + } + + tre->priv = NULL; + + infoPtr = descriptions->descriptions; + while (infoPtr && (infoPtr->description != NULL)) + { + if (numDescriptions == descriptions->defaultIndex) + { + nitf_TREPrivateData *priv = nitf_TREPrivateData_construct(error); + if (!priv) + { + return NITF_FAILURE; + } + + priv->length = length; + priv->description = infoPtr->description; + + if (!nitf_TREPrivateData_setDescriptionName( + priv, infoPtr->name, error + ) + ) + { + nitf_TREPrivateData_destruct(&priv); + return NITF_FAILURE; + } + + tre->priv = priv; + break; + } + numDescriptions++; + infoPtr++; + } + + if (!tre->priv) + { + nitf_Error_init(error, "TRE Description is NULL", + NITF_CTXT, NITF_ERR_INVALID_OBJECT); + return NITF_FAILURE; + } + + return NITF_SUCCESS; +} + +NITFAPI(NITF_BOOL) nitf_TREUtils_fillData(nitf_TRE * tre, + const nitf_TREDescription* descrip, + nitf_Error * error) +{ + nitf_TRECursor cursor; + + /* set the description so the cursor can use it */ + ((nitf_TREPrivateData*)tre->priv)->description = + (nitf_TREDescription*)descrip; + + /* loop over the description, and add blank fields for the + * "normal" fields... any special case fields (loops, conditions) + * won't be added here + */ + cursor = nitf_TRECursor_begin(tre); + while (!nitf_TRECursor_isDone(&cursor)) + { + if (nitf_TRECursor_iterate(&cursor, error)) + { + nitf_Pair* pair = nitf_HashTable_find( + ((nitf_TREPrivateData*)tre->priv)->hash, cursor.tag_str); + + if (!pair || !pair->data) + { + nitf_Field* field = NULL; + int fieldLength = cursor.length; + + /* If it is a GOBBLE length, there isn't really a standard + * on how long it can be... therefore we'll just throw in + * a field of size 1, just to have something... + */ + if (fieldLength == NITF_TRE_GOBBLE) + { + fieldLength = 1; + } + + field = nitf_Field_construct(fieldLength, + cursor.desc_ptr->data_type, + error); + + /* set the field to be resizable later on */ + if (cursor.length == NITF_TRE_GOBBLE) + field->resizable = 1; + + /* special case if BINARY... must set Raw Data */ + if (cursor.desc_ptr->data_type == NITF_BINARY) + { + char* tempBuf = (char *) NITF_MALLOC(fieldLength); + if (!tempBuf) + { + nitf_Field_destruct(&field); + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + goto CATCH_ERROR; + } + + memset(tempBuf, 0, fieldLength); + nitf_Field_setRawData(field, (NITF_DATA *) tempBuf, + fieldLength, error); + } + else if (cursor.desc_ptr->data_type == NITF_BCS_N) + { + /* this will get zero/blank filled by the function */ + nitf_Field_setString(field, "0", error); + } + else + { + /* this will get zero/blank filled by the function */ + nitf_Field_setString(field, " ", error); + } + + /* add to hash if there wasn't an entry yet */ + if (!pair) + { + nitf_HashTable_insert( + ((nitf_TREPrivateData*)tre->priv)->hash, + cursor.tag_str, field, error); + } + /* otherwise, just set the data pointer */ + else + { + pair->data = (NITF_DATA *) field; + } + } + } + } + nitf_TRECursor_cleanup(&cursor); + + /* no problems */ + /* return tre->descrip; */ + return NITF_SUCCESS; + + CATCH_ERROR: + return NITF_FAILURE; +} + +NITFAPI(int) nitf_TREUtils_print(nitf_TRE * tre, nitf_Error * error) +{ + nitf_Pair *pair; /* temp pair */ + int status = NITF_SUCCESS; + nitf_TRECursor cursor; + + /* get out if TRE is null */ + if (!tre) + { + nitf_Error_init(error, "print -> invalid tre object", + NITF_CTXT, NITF_ERR_INVALID_PARAMETER); + return NITF_FAILURE; + } + + cursor = nitf_TRECursor_begin(tre); + while (!nitf_TRECursor_isDone(&cursor) && (status == NITF_SUCCESS)) + { + if ((status = nitf_TRECursor_iterate(&cursor, error)) == NITF_SUCCESS) + { + pair = nitf_HashTable_find( + ((nitf_TREPrivateData*)tre->priv)->hash, cursor.tag_str); + if (!pair || !pair->data) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_UNK, + "Unable to find tag, '%s', in TRE hash for TRE '%s'", cursor.tag_str, tre->tag); + status = NITF_FAILURE; + } + else + { + printf("%s (%s) = [", + cursor.desc_ptr->label == NULL ? + "null" : cursor.desc_ptr->label, cursor.tag_str); + nitf_Field_print((nitf_Field *) pair->data); + printf("]\n"); + } + } + } + nitf_TRECursor_cleanup(&cursor); + return status; +} +NITFAPI(int) nitf_TREUtils_computeLength(nitf_TRE * tre) +{ + int length = 0; + int tempLength; + nitf_Error error; + nitf_Pair *pair; /* temp nitf_Pair */ + nitf_Field *field; /* temp nitf_Field */ + nitf_TRECursor cursor; + + /* get out if TRE is null */ + if (!tre) + return -1; + + cursor = nitf_TRECursor_begin(tre); + while (!nitf_TRECursor_isDone(&cursor)) + { + if (nitf_TRECursor_iterate(&cursor, &error) == NITF_SUCCESS) + { + tempLength = cursor.length; + if (tempLength == NITF_TRE_GOBBLE) + { + /* we don't have any other way to know the length of this + * field, other than to see if the field is in the hash + * and use the length defined when it was created. + * Otherwise, we don't add any length. + */ + tempLength = 0; + pair = nitf_HashTable_find( + ((nitf_TREPrivateData*)tre->priv)->hash, cursor.tag_str); + if (pair) + { + field = (nitf_Field *) pair->data; + if (field) + tempLength = field->length; + } + } + length += tempLength; + } + } + nitf_TRECursor_cleanup(&cursor); + return length; +} + +NITFAPI(NITF_BOOL) nitf_TREUtils_isSane(nitf_TRE * tre) +{ + int status = 1; + nitf_Error error; + nitf_TRECursor cursor; + + /* get out if TRE is null */ + if (!tre) + return NITF_FAILURE; + + cursor = nitf_TRECursor_begin(tre); + while (!nitf_TRECursor_isDone(&cursor) && status) + { + if (nitf_TRECursor_iterate(&cursor, &error) == NITF_SUCCESS) + if (!nitf_TRE_exists(tre, cursor.tag_str)) + status = !status; + } + nitf_TRECursor_cleanup(&cursor); + return status; +} + +NITFAPI(NITF_BOOL) nitf_TREUtils_basicRead(nitf_IOInterface* io, + nitf_Uint32 length, + nitf_TRE* tre, + struct _nitf_Record* record, + nitf_Error* error) +{ + int ok; + char *data = NULL; + nitf_TREDescriptionSet *descriptions = NULL; + nitf_TREDescriptionInfo *infoPtr = NULL; + + if (!tre) + return NITF_FAILURE; + + /* set the description/length */ + /*nitf_TREUtils_setDescription(tre, length, error);*/ + + /*if (!tre->descrip) goto CATCH_ERROR;*/ + data = (char*)NITF_MALLOC( length ); + if (!data) + { + nitf_Error_init(error, NITF_STRERROR( NITF_ERRNO ),NITF_CTXT, NITF_ERR_MEMORY ); + return NITF_FAILURE; + } + memset(data, 0, length); + if (!nitf_TREUtils_readField(io, data, length, error)) + { + NITF_FREE(data); + return NITF_FAILURE; + } + + descriptions = (nitf_TREDescriptionSet*)tre->handler->data; + + if (!descriptions) + { + nitf_Error_init(error, "TRE Description Set is NULL", + NITF_CTXT, NITF_ERR_INVALID_OBJECT); + + NITF_FREE(data); + return NITF_FAILURE; + } + + tre->priv = NULL; + infoPtr = descriptions->descriptions; + tre->priv = nitf_TREPrivateData_construct(error); + ((nitf_TREPrivateData*)tre->priv)->length = length; + + ok = NITF_FAILURE; + while (infoPtr && (infoPtr->description != NULL)) + { + if (!tre->priv) + { + break; + } + + ((nitf_TREPrivateData*)tre->priv)->description = infoPtr->description; +#ifdef NITF_DEBUG + printf("Trying TRE with description: %s\n\n", infoPtr->name); +#endif + ok = nitf_TREUtils_parse(tre, data, error); + if (ok) + { + nitf_TREPrivateData *priv = (nitf_TREPrivateData*)tre->priv; + /* copy the name */ + if (!nitf_TREPrivateData_setDescriptionName( + priv, infoPtr->name, error)) + { + /* something bad happened... so we need to cleanup */ + NITF_FREE(data); + nitf_TREPrivateData_destruct(&priv); + tre->priv = NULL; + return NITF_FAILURE; + } + + /*nitf_HashTable_print( ((nitf_TREPrivateData*)tre->priv)->hash );*/ + break; + } + + infoPtr++; + } + + + + if (data) NITF_FREE(data); + return ok; +} + +NITFAPI(NITF_BOOL) nitf_TREUtils_basicInit(nitf_TRE * tre, + const char* id, + nitf_Error * error) +{ + nitf_TREDescriptionSet* set = NULL; + nitf_TREDescriptionInfo* descInfo = NULL; + nitf_TREPrivateData *priv = NULL; + NITF_BOOL found = 0; + + assert(tre); + + set = (nitf_TREDescriptionSet*)tre->handler->data; + + /* create a new private data struct */ + priv = nitf_TREPrivateData_construct(error); + if (!priv) + return NITF_FAILURE; + + /* search for the description with the given ID - if one was provided */ + if (id) + { + descInfo = set->descriptions; + + while(descInfo && descInfo->name && !found) + { + if (strcmp(descInfo->name, id) == 0) + { + /* we have a match! */ + found = 1; + } + else + { + descInfo++; + } + } + + /* if we couldn't find it, we get out of here... */ + if (!found) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_INVALID_OBJECT, + "No matching id '%s' found!", id); + return NITF_FAILURE; + } + } + else + { + /* otherwise, if no ID was given, we'll just use the first description. + * in most cases, this will be the only description. + */ + descInfo = set->descriptions; + } + + /* set the name */ + if (!nitf_TREPrivateData_setDescriptionName( + priv, descInfo->name, error)) + { + nitf_TREPrivateData_destruct(&priv); + tre->priv = NULL; + return NITF_FAILURE; + } + + /* assign it to the TRE */ + tre->priv = priv; + + /* try to fill the TRE */ + if (nitf_TREUtils_fillData(tre, descInfo->description, error)) + return NITF_SUCCESS; + else + { + nitf_TRE_destruct(&tre); + return NITF_FAILURE; + } +} + +NITFAPI(NITF_BOOL) nitf_TREUtils_basicWrite(nitf_IOInterface* io, + nitf_TRE* tre, + struct _nitf_Record* record, + nitf_Error* error) +{ + nitf_Uint32 length; + char* data = NULL; + NITF_BOOL ok = NITF_FAILURE; + + data = nitf_TREUtils_getRawData(tre, &length, error); + if (data) + { + ok = nitf_IOInterface_write(io, data, length, error); + NITF_FREE(data); + } + return ok; +} + +NITFAPI(int) nitf_TREUtils_basicGetCurrentSize(nitf_TRE* tre, + nitf_Error* error) +{ + return nitf_TREUtils_computeLength(tre); +} + +NITFAPI(const char*) nitf_TREUtils_basicGetID(nitf_TRE *tre) +{ + return ((nitf_TREPrivateData*)tre->priv)->descriptionName; +} + + +NITFAPI(NITF_BOOL) nitf_TREUtils_basicClone(nitf_TRE *source, + nitf_TRE *tre, + nitf_Error *error) +{ + nitf_TREPrivateData *sourcePriv = NULL; + nitf_TREPrivateData *trePriv = NULL; + + if (!tre || !source || !source->priv) + return NITF_FAILURE; + + sourcePriv = (nitf_TREPrivateData*)source->priv; + + /* this clones the hash */ + if (!(trePriv = nitf_TREPrivateData_clone(sourcePriv, error))) + return NITF_FAILURE; + + /* just copy over the optional length and static description */ + trePriv->length = sourcePriv->length; + trePriv->description = sourcePriv->description; + + tre->priv = (NITF_DATA*)trePriv; + + return NITF_SUCCESS; +} + + +NITFAPI(void) nitf_TREUtils_basicDestruct(nitf_TRE* tre) +{ + if (tre && tre->priv) + nitf_TREPrivateData_destruct((nitf_TREPrivateData**)&tre->priv); +} + +/* + * TODO: Can DefaultTRE use these now that they're not private? + * + */ +NITFAPI(nitf_List*) nitf_TREUtils_basicFind(nitf_TRE* tre, + const char* pattern, + nitf_Error* error) +{ + nitf_List* list; + + nitf_HashTableIterator it = nitf_HashTable_begin( + ((nitf_TREPrivateData*)tre->priv)->hash); + nitf_HashTableIterator end = nitf_HashTable_end( + ((nitf_TREPrivateData*)tre->priv)->hash); + + list = nitf_List_construct(error); + if (!list) return NULL; + + while (nitf_HashTableIterator_notEqualTo(&it, &end)) + { + nitf_Pair* pair = nitf_HashTableIterator_get(&it); + + if (strstr(pair->key, pattern)) + { + /* Should check this, I suppose */ + nitf_List_pushBack(list, pair, error); + + } + nitf_HashTableIterator_increment(&it); + } + + return list; +} + +NITFAPI(NITF_BOOL) nitf_TREUtils_basicSetField(nitf_TRE* tre, + const char* tag, + NITF_DATA* data, + size_t dataLength, + nitf_Error* error) +{ + return nitf_TREUtils_setValue(tre, tag, data, dataLength, error); +} + +NITFAPI(nitf_Field*) nitf_TREUtils_basicGetField(nitf_TRE* tre, + const char* tag) +{ + nitf_Pair* pair = nitf_HashTable_find( + ((nitf_TREPrivateData*)tre->priv)->hash, tag); + if (!pair) return NULL; + return (nitf_Field*)pair->data; +} + +NITFPRIV(nitf_Pair*) basicIncrement(nitf_TREEnumerator* it, nitf_Error* error) +{ + /* get the next value, and increment the cursor */ + nitf_TRECursor* cursor = it ? (nitf_TRECursor*)it->data : NULL; + nitf_Pair* data; + + if (!cursor || !nitf_TRECursor_iterate(cursor, error)) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_INVALID_OBJECT, + "Invalid cursor, or error iterating..."); + return NULL; + } + + if (!nitf_TRE_exists(cursor->tre, cursor->tag_str)) + goto CATCH_ERROR; + + data = nitf_HashTable_find(((nitf_TREPrivateData*)cursor->tre->priv)->hash, + cursor->tag_str); + if (!data) + goto CATCH_ERROR; + + return data; + + CATCH_ERROR: + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_INVALID_OBJECT, + "Couldnt retrieve tag [%s]", cursor->tag_str); + return NULL; +} + +NITFPRIV(NITF_BOOL) basicHasNext(nitf_TREEnumerator** it) +{ + nitf_TRECursor* cursor = it && *it ? (nitf_TRECursor*)(*it)->data : NULL; + if (cursor && nitf_TRECursor_isDone(cursor)) + { + nitf_TRECursor_cleanup(cursor); + NITF_FREE(cursor); + NITF_FREE(*it); + *it = NULL; + return NITF_FAILURE; /* maybe 0 is better */ + } + return cursor != NULL ? NITF_SUCCESS : NITF_FAILURE; +} + +NITFPRIV(const char*) basicGetFieldDescription(nitf_TREEnumerator* it, + nitf_Error* error) +{ + nitf_TRECursor* cursor = it ? (nitf_TRECursor*)(it->data) : NULL; + if (cursor && cursor->desc_ptr && cursor->desc_ptr->label) + { + return cursor->desc_ptr->label; + } + nitf_Error_init(error, "No TRE Description available", + NITF_CTXT, NITF_ERR_INVALID_OBJECT); + return NULL; +} + +NITFAPI(nitf_TREEnumerator*) nitf_TREUtils_basicBegin(nitf_TRE* tre, + nitf_Error* error) +{ + nitf_TREEnumerator* it = + (nitf_TREEnumerator*)NITF_MALLOC(sizeof(nitf_TREEnumerator)); + nitf_TRECursor* cursor = + (nitf_TRECursor*)NITF_MALLOC(sizeof(nitf_TRECursor)); + *cursor = nitf_TRECursor_begin(tre); + /*assert(nitf_TRECursor_iterate(cursor, error));*/ + + it->data = cursor; + it->next = basicIncrement; + it->hasNext = basicHasNext; + it->getFieldDescription = basicGetFieldDescription; + return it; +} + +NITFAPI(nitf_TREHandler*) +nitf_TREUtils_createBasicHandler(nitf_TREDescriptionSet* set, + nitf_TREHandler *handler, + nitf_Error* error) +{ + handler->init = nitf_TREUtils_basicInit; + handler->getID = nitf_TREUtils_basicGetID; + handler->read = nitf_TREUtils_basicRead; + handler->setField = nitf_TREUtils_basicSetField; + handler->getField = nitf_TREUtils_basicGetField; + handler->find = nitf_TREUtils_basicFind; + handler->write = nitf_TREUtils_basicWrite; + handler->begin = nitf_TREUtils_basicBegin; + handler->getCurrentSize = nitf_TREUtils_basicGetCurrentSize; + handler->clone = nitf_TREUtils_basicClone; + handler->destruct = nitf_TREUtils_basicDestruct; + + handler->data = set; + return handler; +} diff --git a/modules/c/nitf/source/TextSegment.c b/modules/c/nitf/source/TextSegment.c new file mode 100644 index 000000000..f427c2838 --- /dev/null +++ b/modules/c/nitf/source/TextSegment.c @@ -0,0 +1,112 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/TextSegment.h" + +NITFAPI(nitf_TextSegment *) nitf_TextSegment_construct(nitf_Error * error) +{ + nitf_TextSegment *segment = + (nitf_TextSegment *) NITF_MALLOC(sizeof(nitf_TextSegment)); + + if (!segment) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + return NULL; + } + + /* The text offset in the file */ + segment->offset = 0; + /* The text end (offset + length text) */ + segment->end = 0; + + /* This object gets created NOW */ + segment->subheader = NULL; + segment->subheader = nitf_TextSubheader_construct(error); + if (!segment->subheader) + { + nitf_TextSegment_destruct(&segment); + return NULL; + } + /* Yes! We have a success */ + return segment; +} + + +NITFAPI(nitf_TextSegment *) nitf_TextSegment_clone(nitf_TextSegment * + source, + nitf_Error * error) +{ + nitf_TextSegment *segment = NULL; + + if (source) + { + segment = + (nitf_TextSegment *) NITF_MALLOC(sizeof(nitf_TextSegment)); + + if (!segment) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + return NULL; + } + /* The text offset in the file */ + segment->offset = source->offset; + /* The text end (offset + length text) */ + segment->end = source->end; + + /* Just in case we self-destruct */ + segment->subheader = + nitf_TextSubheader_clone(source->subheader, error); + if (!segment->subheader) + { + nitf_TextSegment_destruct(&segment); + return NULL; + } + } + else + { + nitf_Error_initf(error, + NITF_CTXT, + NITF_ERR_INVALID_OBJECT, + "Trying to clone NULL pointer"); + } + /* Yes! We have a success */ + return segment; +} + + +NITFAPI(void) nitf_TextSegment_destruct(nitf_TextSegment ** segment) +{ + if (*segment) + { + if ((*segment)->subheader) + { + /* Destroy subheader info */ + nitf_TextSubheader_destruct(&(*segment)->subheader); + } + + NITF_FREE(*segment); + *segment = NULL; + + } +} diff --git a/modules/c/nitf/source/TextSubheader.c b/modules/c/nitf/source/TextSubheader.c new file mode 100644 index 000000000..fd51fc0b6 --- /dev/null +++ b/modules/c/nitf/source/TextSubheader.c @@ -0,0 +1,174 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/TextSubheader.h" + +#define _NITF_CONSTRUCT_FIELD(OWNER, ID, TYPE) \ + OWNER->ID = nitf_Field_construct(ID##_SZ, TYPE, error); \ + if (!OWNER->ID) goto CATCH_ERROR; + +#define _NITF_CLONE_FIELD(DEST, SOURCE, ID) \ + DEST->ID = nitf_Field_clone(SOURCE->ID, error); \ + if (!DEST->ID) goto CATCH_ERROR; + +#define _NITF_DESTRUCT_FIELD(OWNER, ID) \ + if (OWNER->ID) nitf_Field_destruct(OWNER->ID); + +NITFAPI(nitf_TextSubheader *) +nitf_TextSubheader_construct(nitf_Error * error) +{ + /* Start by allocating the header */ + nitf_TextSubheader *subhdr = (nitf_TextSubheader *) + NITF_MALLOC(sizeof(nitf_TextSubheader)); + + /* Return now if we have a problem above */ + if (!subhdr) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + + return NULL; + } + + subhdr->extendedSection = NULL; + subhdr->securityGroup = nitf_FileSecurity_construct(error); + if (!subhdr->securityGroup) + { + nitf_TextSubheader_destruct(&subhdr); + goto CATCH_ERROR; + } + + _NITF_CONSTRUCT_FIELD(subhdr, NITF_TE, NITF_BCS_A); + _NITF_CONSTRUCT_FIELD(subhdr, NITF_TEXTID, NITF_BCS_A); + + _NITF_CONSTRUCT_FIELD(subhdr, NITF_TXTALVL, NITF_BCS_N); + + _NITF_CONSTRUCT_FIELD(subhdr, NITF_TXTDT, NITF_BCS_A); + _NITF_CONSTRUCT_FIELD(subhdr, NITF_TXTITL, NITF_BCS_A); + _NITF_CONSTRUCT_FIELD(subhdr, NITF_TSCLAS, NITF_BCS_A); + + _NITF_CONSTRUCT_FIELD(subhdr, NITF_ENCRYP, NITF_BCS_A); + _NITF_CONSTRUCT_FIELD(subhdr, NITF_TXTFMT, NITF_BCS_A); + + _NITF_CONSTRUCT_FIELD(subhdr, NITF_TXSHDL, NITF_BCS_N); + _NITF_CONSTRUCT_FIELD(subhdr, NITF_TXSOFL, NITF_BCS_N); + + subhdr->extendedSection = nitf_Extensions_construct(error); + if (!subhdr->extendedSection) + goto CATCH_ERROR; + + return subhdr; + +CATCH_ERROR: + nitf_TextSubheader_destruct(&subhdr); + return NULL; +} + + +NITFAPI(nitf_TextSubheader *) +nitf_TextSubheader_clone(nitf_TextSubheader * source, nitf_Error * error) +{ + nitf_TextSubheader *subhdr = NULL; + if (source) + { + subhdr = + (nitf_TextSubheader *) NITF_MALLOC(sizeof(nitf_TextSubheader)); + if (!subhdr) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + return NULL; + } + + subhdr->securityGroup = + nitf_FileSecurity_clone(source->securityGroup, error); + + if (!subhdr->securityGroup) + goto CATCH_ERROR; + + /* Copy some fields */ + _NITF_CLONE_FIELD(subhdr, source, NITF_TE); + _NITF_CLONE_FIELD(subhdr, source, NITF_TEXTID); + + _NITF_CLONE_FIELD(subhdr, source, NITF_TXTALVL); + + _NITF_CLONE_FIELD(subhdr, source, NITF_TXTDT); + _NITF_CLONE_FIELD(subhdr, source, NITF_TXTITL); + _NITF_CLONE_FIELD(subhdr, source, NITF_TSCLAS); + + _NITF_CLONE_FIELD(subhdr, source, NITF_ENCRYP); + _NITF_CLONE_FIELD(subhdr, source, NITF_TXTFMT); + + _NITF_CLONE_FIELD(subhdr, source, NITF_TXSHDL); + _NITF_CLONE_FIELD(subhdr, source, NITF_TXSOFL); + + /* init to NULL in case */ + subhdr->extendedSection = NULL; + + if (source->extendedSection) + { + subhdr->extendedSection = + nitf_Extensions_clone(source->extendedSection, error); + + if (!subhdr->extendedSection) + goto CATCH_ERROR; + } + + return subhdr; + } + +CATCH_ERROR: + nitf_TextSubheader_destruct(&subhdr); + return NULL; +} + + +NITFAPI(void) nitf_TextSubheader_destruct(nitf_TextSubheader ** subhdr) +{ + if (!*subhdr) + return; + + if ((*subhdr)->extendedSection) + { + nitf_Extensions_destruct(&(*subhdr)->extendedSection); + } + if ((*subhdr)->securityGroup) + { + nitf_FileSecurity_destruct(&(*subhdr)->securityGroup); + NITF_FREE((*subhdr)->securityGroup); + (*subhdr)->securityGroup = NULL; + } + + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_TE); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_TEXTID); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_TXTALVL); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_TXTDT); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_TXTITL); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_TSCLAS); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_ENCRYP); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_TXTFMT); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_TXSHDL); + _NITF_DESTRUCT_FIELD(&(*subhdr), NITF_TXSOFL); + + NITF_FREE(*subhdr); + *subhdr = NULL; +} diff --git a/modules/c/nitf/source/WriteHandler.c b/modules/c/nitf/source/WriteHandler.c new file mode 100644 index 000000000..5788b04e5 --- /dev/null +++ b/modules/c/nitf/source/WriteHandler.c @@ -0,0 +1,35 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/WriteHandler.h" + + +NITFAPI(void) nitf_WriteHandler_destruct(nitf_WriteHandler ** writeHandler) +{ + if (*writeHandler) + { + if ((*writeHandler)->iface) + (*writeHandler)->iface->destruct((*writeHandler)->data); + NITF_FREE(*writeHandler); + *writeHandler = NULL; + } +} diff --git a/modules/c/nitf/source/Writer.c b/modules/c/nitf/source/Writer.c new file mode 100644 index 000000000..8d95e4d6c --- /dev/null +++ b/modules/c/nitf/source/Writer.c @@ -0,0 +1,2437 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nitf/Writer.h" + +/* This writer basically allows exceptions. It uses the */ +/* error object of the given Writer, thus simplifying the*/ +/* code. Many of the MACROS used in this file should be */ +/* used throughout any helper functions, but be careful */ +/* with it. You must note the assumptions. */ +/* ASSUMPTIONS: */ +/* 1) A nitf_Writer object named writer exists */ +/* 2) A parseInfo object exists */ +/* 3) A label is in scope called CATCH_ERROR */ + +/* These define chars for filling fields */ +#define SPACE ' ' +#define ZERO '0' +#define FILL_LEFT 1 +#define FILL_RIGHT 2 + +/* define some maximum data lengths */ +#define NITF_MAX_IMAGE_LENGTH NITF_INT64(9999999999) + +/* This is the size of each num* (numi, numx, nums, numdes, numres) */ +#define NITF_IVAL_SZ 3 + +/* This MACRO writes the given value, and pads it as specified */ +/* Example: NITF_WRITE_VALUE(io, securityGroup, NITF_CLSY, SPACE, FILL_RIGHT); */ +/* It jumps to the CATCH_ERROR label if an error occurs. */ +#define NITF_WRITE_VALUE(own_, fld_, fil_, dir_) \ + if (!writeValue(writer, own_->fld_, fld_##_SZ, fil_, dir_, error)) \ + goto CATCH_ERROR; + +#define NITF_WRITE_STR_FIELD(own_, fld_, fil_, dir_) \ + if (!writeStringField(writer, own_->fld_, fld_##_SZ, fil_, dir_, error)) \ + goto CATCH_ERROR; + +#define NITF_WRITE_INT_FIELD(value_, fld_, fil_, dir_) \ + if (!writeIntField(writer, value_, fld_##_SZ, fil_, dir_, error)) \ + goto CATCH_ERROR; + +#define NITF_WRITE_INT64_FIELD(value_, fld_, fil_, dir_) \ + if (!writeInt64Field(writer, value_, fld_##_SZ, fil_, dir_, error)) \ + goto CATCH_ERROR; + + + +/* We use the writeComponentInfo() method underneath this */ +/* method, as we do for all of the components. The macro */ +/* allows us to specialize this functionality for images */ +#define NITF_WRITE_IMAGE_INFO(com_,num_) \ + if (!writeComponentInfo(writer, com_, num_, \ + NITF_LISH_SZ, NITF_LI_SZ, error)) \ + goto CATCH_ERROR; + +/* We use the writeComponentInfo() method underneath this */ +/* method, as we do for all of the components. The macro */ +/* allows us to specialize this functionality for */ +/* graphics */ +#define NITF_WRITE_GRAPHICS_INFO(com_,num_) \ + if (!writeComponentInfo(writer, com_, num_, \ + NITF_LSSH_SZ, NITF_LS_SZ, error)) \ + goto CATCH_ERROR; + +/* The label info for the 2.1 file appears to be a riddle */ +/* wrapped in enigma, shrouded in mystery. It is a blank */ +/* space that is set to 000, and therefore, while */ +/* technically a component info section, not meaningful */ +/* whatsoever. Still, we use the writeComponentInfo() */ +/* method underneath to write it. */ +#define NITF_WRITE_LABEL_INFO(com_,num_) \ + if (!writeComponentInfo(writer, com_, num_, 0, 0, error)) \ + goto CATCH_ERROR; + +/* We use the writeComponentInfo() method underneath this */ +/* method, as we do for all of the components. The macro */ +/* allows us to specialize this functionality for texts */ +#define NITF_WRITE_TEXT_INFO(com_,num_) \ + if (!writeComponentInfo(writer, com_, num_, \ + NITF_LTSH_SZ, NITF_LT_SZ, error)) \ + goto CATCH_ERROR; + +/* We use the writeComponentInfo() method underneath this */ +/* method, as we do for all of the components. The macro */ +/* allows us to specialize this functionality for data */ +/* extension segments */ +#define NITF_WRITE_DATA_EXT_INFO(com_,num_) \ + if (!writeComponentInfo(writer, com_, num_, \ + NITF_LDSH_SZ, NITF_LD_SZ, error)) \ + goto CATCH_ERROR; + +/* We use the writeComponentInfo() method underneath this */ +/* method, as we do for all of the components. The macro */ +/* allows us to specialize this functionality for */ +/* reserved extension segments */ +#define NITF_WRITE_RES_EXT_INFO(com_,num_) \ + if (!writeComponentInfo(writer, com_, num_, \ + NITF_LRESH_SZ, NITF_LRE_SZ, error)) \ + goto CATCH_ERROR; + +/* This macro makes it easier to write the user-defined */ +/* header data section. The writeExtras() method supplies*/ +/* the underlying driving call, but it can be generalized */ +/* for this case, and for the extended header components */ +#define NITF_WRITE_USER_HDR_INFO(ext_,hdl_,ofl_) \ + if (!writeExtras(writer, ext_, hdl_, ofl_, \ + NITF_UDHDL_SZ, NITF_UDHOFL_SZ, error)) \ + goto CATCH_ERROR; + +/* This macro makes it easier to write the extended */ +/* header data section. The writeExtras() method supplies*/ +/* the underlying driving call, but it can be generalized */ +/* for this case, and for the extended header components */ +#define NITF_WRITE_EXT_HDR_INFO(ext_,hdl_,ofl_) \ + if (!writeExtras(writer, ext_, hdl_, ofl_, \ + NITF_XHDL_SZ, NITF_XHDLOFL_SZ, error)) \ + goto CATCH_ERROR; + +/* ------------------------------------------------------------------ */ +/* PRIVATE PROTOTYPES */ +/* ------------------------------------------------------------------ */ + +/* This is a simple write method. Note that this is NOT a finalized */ +/* method. It is simply pending on error handling. Exiting is not */ +/* even an option. */ +NITFPRIV(NITF_BOOL) writeField(nitf_Writer * writer, + char *field, + nitf_Uint32 length, nitf_Error * error); + +/* Pads a string with a fill character */ +/* fld The input string */ +/* fill The fill character */ +/* length The total length of the string */ +/* fillDir The fill direction (either FILL_LEFT or FILL_RIGHT) */ +NITFPRIV(NITF_BOOL) padString(nitf_Writer * writer, + char *field, + nitf_Uint32 length, + char fill, + const nitf_Uint32 fillDir, + nitf_Error * error); + +/* Writes the given TRE */ +NITFPRIV(NITF_BOOL) writeExtension(nitf_Writer * writer, + nitf_TRE * tre, nitf_Error * error); + +/* ------------------------------------------------------------------ */ +/* PRIVATE AREA */ +/* ------------------------------------------------------------------ */ + +NITFPRIV(void) resetIOInterface(nitf_Writer * writer) +{ + if (writer->output && writer->ownOutput) + nitf_IOInterface_destruct( &(writer->output) ); + writer->output = NULL; + writer->ownOutput = 0; +} + +NITFPRIV(NITF_BOOL) writeStringField(nitf_Writer * writer, + char *field, + nitf_Uint32 length, + char fill, + const nitf_Uint32 fillDir, + nitf_Error * error) +{ + char *buf = (char *) NITF_MALLOC(length + 1); + if (!buf) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + goto CATCH_ERROR; + } + + memset(buf, '\0', length + 1); + memcpy(buf, field, length); + + if (!padString(writer, buf, length, fill, fillDir, error)) + goto CATCH_ERROR; + + if (!writeField(writer, buf, length, error)) + goto CATCH_ERROR; + + NITF_FREE(buf); + return NITF_SUCCESS; + +CATCH_ERROR: + if (buf) NITF_FREE(buf); + return NITF_FAILURE; +} + + +NITFPRIV(NITF_BOOL) writeValue(nitf_Writer * writer, + nitf_Field * field, + nitf_Uint32 length, + char fill, + const nitf_Uint32 fillDir, + nitf_Error * error) +{ + char *buf = (char *) NITF_MALLOC(length + 1); + if (!buf) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + goto CATCH_ERROR; + } + + memset(buf, '\0', length + 1); + + /* first, check to see if we need to swap bytes */ + if (field->type == NITF_BINARY) + { + if (length == NITF_INT16_SZ) + { + nitf_Int16 int16 = + (nitf_Int16)NITF_HTONS(*((nitf_Int16 *) field->raw)); + memcpy(buf, (char*)&int16, length); + } + else if (length == NITF_INT32_SZ) + { + nitf_Int32 int32 = + (nitf_Int32)NITF_HTONL(*((nitf_Int32 *) field->raw)); + memcpy(buf, (char*)&int32, length); + } + else + { + /* TODO what to do??? 8 bit is ok, but what about 64? */ + memcpy(buf, field->raw, length); + } + + /* we do not pad binary values, for obvious reasons... */ + } + else + { + memcpy(buf, field->raw, length); + + if (!padString(writer, buf, length, fill, fillDir, error)) + goto CATCH_ERROR; + } + + if (!writeField(writer, buf, length, error)) + goto CATCH_ERROR; + + NITF_FREE(buf); + return NITF_SUCCESS; + +CATCH_ERROR: + if (buf) NITF_FREE(buf); + return NITF_FAILURE; +} + + +NITFPRIV(NITF_BOOL) writeIntField(nitf_Writer * writer, + nitf_Uint32 field, + nitf_Uint32 length, + char fill, + const nitf_Uint32 fillDir, + nitf_Error * error) +{ + char buf[20]; + + memset(buf, '\0', 20); + NITF_SNPRINTF(buf, 20, "%d", field); + + if (padString(writer, buf, length, fill, fillDir, error)) + { + return writeField(writer, buf, length, error); + } + + /* error padding */ + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_UNK); + return NITF_FAILURE; +} + + +/* This function pads the given nitf_Uint64, and writes it to the IOHandle */ +NITFPRIV(NITF_BOOL) writeInt64Field(nitf_Writer * writer, + nitf_Uint64 field, + nitf_Uint32 length, + char fill, + const nitf_Uint32 fillDir, + nitf_Error * error) +{ + char buf[20]; + + memset(buf, '\0', 20); + NITF_SNPRINTF(buf, 20, "%lld", (long long int)field); + + if (padString(writer, buf, length, fill, fillDir, error)) + { + return writeField(writer, buf, length, error); + } + + /* error padding */ + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_UNK); + return NITF_FAILURE; +} + + +NITFPRIV(NITF_BOOL) writeField(nitf_Writer * writer, + char *field, + nitf_Uint32 length, + nitf_Error * error) +{ + if (!nitf_IOInterface_write(writer->output, field, length, error)) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_WRITING_TO_FILE); + return NITF_FAILURE; + } + return NITF_SUCCESS; +} + + +/* This function writes NITF 2.0 specific security information */ +NITFPRIV(NITF_BOOL) write20FileSecurity(nitf_Writer * writer, + nitf_FileSecurity * securityGroup, + nitf_Error * error) +{ + if (!writeStringField(writer, securityGroup->NITF_CODE->raw, + NITF_CODE_20_SZ, SPACE, FILL_RIGHT, error)) + goto CATCH_ERROR; + if (!writeStringField(writer, securityGroup->NITF_CTLH->raw, + NITF_CTLH_20_SZ, SPACE, FILL_RIGHT, error)) + goto CATCH_ERROR; + if (!writeStringField(writer, securityGroup->NITF_REL->raw, + NITF_REL_20_SZ, SPACE, FILL_RIGHT, error)) + goto CATCH_ERROR; + if (!writeStringField(writer, securityGroup->NITF_CAUT->raw, + NITF_CAUT_20_SZ, SPACE, FILL_RIGHT, error)) + goto CATCH_ERROR; + if (!writeStringField(writer, securityGroup->NITF_CTLN->raw, + NITF_CTLN_20_SZ, SPACE, FILL_RIGHT, error)) + goto CATCH_ERROR; + if (!writeStringField(writer, securityGroup->NITF_DGDT->raw, + NITF_DGDT_20_SZ, SPACE, FILL_RIGHT, error)) + goto CATCH_ERROR; + + if (strncmp(securityGroup->NITF_DGDT->raw, "999998", 6) == 0) + if (!writeStringField(writer, securityGroup->NITF_CLTX->raw, + NITF_CLTX_20_SZ, ZERO, FILL_LEFT, error)) + goto CATCH_ERROR; + + return NITF_SUCCESS; + +CATCH_ERROR: + return NITF_FAILURE; +} + + +/* This function writes NITF 2.1 specific security information */ +NITFPRIV(NITF_BOOL) write21FileSecurity(nitf_Writer * writer, + nitf_FileSecurity * securityGroup, + nitf_Error * error) +{ + NITF_WRITE_VALUE(securityGroup, NITF_CLSY, SPACE, FILL_RIGHT); + NITF_WRITE_VALUE(securityGroup, NITF_CODE, SPACE, FILL_RIGHT); + NITF_WRITE_VALUE(securityGroup, NITF_CTLH, SPACE, FILL_RIGHT); + NITF_WRITE_VALUE(securityGroup, NITF_REL, SPACE, FILL_RIGHT); + NITF_WRITE_VALUE(securityGroup, NITF_DCTP, SPACE, FILL_RIGHT); + NITF_WRITE_VALUE(securityGroup, NITF_DCDT, SPACE, FILL_RIGHT); + NITF_WRITE_VALUE(securityGroup, NITF_DCXM, SPACE, FILL_RIGHT); + NITF_WRITE_VALUE(securityGroup, NITF_DG, SPACE, FILL_RIGHT); + NITF_WRITE_VALUE(securityGroup, NITF_DGDT, SPACE, FILL_RIGHT); + NITF_WRITE_VALUE(securityGroup, NITF_CLTX, SPACE, FILL_RIGHT); + NITF_WRITE_VALUE(securityGroup, NITF_CATP, SPACE, FILL_RIGHT); + NITF_WRITE_VALUE(securityGroup, NITF_CAUT, SPACE, FILL_RIGHT); + NITF_WRITE_VALUE(securityGroup, NITF_CRSN, SPACE, FILL_RIGHT); + NITF_WRITE_VALUE(securityGroup, NITF_RDT, SPACE, FILL_RIGHT); + NITF_WRITE_VALUE(securityGroup, NITF_CTLN, SPACE, FILL_RIGHT); + + return NITF_SUCCESS; + +CATCH_ERROR: + return NITF_FAILURE; +} + + +/* This function pads the given string with the fill character */ +NITFPRIV(NITF_BOOL) padString(nitf_Writer * writer, + char *field, + nitf_Uint32 length, + char fill, + const nitf_Uint32 fillDir, + nitf_Error * error) +{ + /* size and remainder */ + size_t size = 0, offset = 0; + + /* check to see if we even need to pad it */ + if (!field) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_INVALID_PARAMETER, + "Trying to use NULL field. padString failed."); + return NITF_FAILURE; + } + size = (nitf_Uint32)strlen(field); + if (size >= length) + { + /* Dont need to pad at all */ + return NITF_SUCCESS; /* No error occurred */ + } + + offset = (size_t)length - size; + /* Set the buffer to the fill character */ + if (fillDir == FILL_RIGHT) + { + memset((char*)(field + size), fill, offset); + } + else if (fillDir == FILL_LEFT) + { + memmove((char*)(field + offset), field, size); + memset(field, fill, offset); + } + field[length] = '\0'; + + return NITF_SUCCESS; +} + + +/* This function writes the given ComponentInfo section */ +NITFPRIV(NITF_BOOL) writeComponentInfo(nitf_Writer * writer, + nitf_ComponentInfo ** info, + nitf_Uint32 num, + nitf_Uint32 subHdrSize, + nitf_Uint32 segmentSize, + nitf_Error * error) +{ + nitf_Uint32 i; + + /* First, write the num* */ + if (!writeIntField(writer, num, NITF_IVAL_SZ, ZERO, FILL_LEFT, error)) + goto CATCH_ERROR; + + /* Write the image info */ + for (i = 0; i < num; i++) + { + if (!writeStringField(writer, info[i]->lengthSubheader->raw, + subHdrSize, ZERO, FILL_LEFT, error)) + goto CATCH_ERROR; + if (!writeStringField(writer, info[i]->lengthData->raw, + segmentSize, ZERO, FILL_LEFT, error)) + goto CATCH_ERROR; + } + + return NITF_SUCCESS; + + /* Error */ +CATCH_ERROR: + return NITF_FAILURE; +} + + +/* This function writes the given Extensions */ +NITFPRIV(NITF_BOOL) writeExtras(nitf_Writer * writer, + nitf_Extensions * section, + nitf_Uint32 * dataLength, + nitf_Uint32 * dataOverflow, + const nitf_Uint32 hdlFieldSize, + const nitf_Uint32 oflFieldSize, + nitf_Error * error) +{ + nitf_ExtensionsIterator iter, end; + size_t totalLength = 0; + nitf_Version version; + nitf_TRE *tre = NULL; + + /* get the version */ + version = nitf_Record_getVersion(writer->record); + + /* compute the length of the section */ + totalLength = nitf_Extensions_computeLength(section, version, error); + + /* must add the oflFieldSize if we have non-zero data length */ + *dataLength = (totalLength > 0 || *dataOverflow != 0) ? + totalLength + oflFieldSize : totalLength; + + /* First, write length and overflow fields */ + if (!writeIntField(writer, *dataLength, hdlFieldSize, + ZERO, FILL_LEFT, error)) + goto CATCH_ERROR; + + if (*dataLength != 0) + { + if (!writeIntField(writer, *dataOverflow, + oflFieldSize, ZERO, FILL_LEFT, error)) + goto CATCH_ERROR; + } + + if (section != NULL) + { + /* set up iterators */ + iter = nitf_Extensions_begin(section); + end = nitf_Extensions_end(section); + + /* Now, write the TREs */ + while (nitf_ExtensionsIterator_notEqualTo(&iter, &end)) + { + tre = (nitf_TRE *) nitf_ExtensionsIterator_get(&iter); + + /* write it! */ + if (!writeExtension(writer, tre, error)) + goto CATCH_ERROR; + + /* increment */ + nitf_ExtensionsIterator_increment(&iter); + } + } + + /* Normal completion */ + return NITF_SUCCESS; + + /* Error */ +CATCH_ERROR: + return NITF_FAILURE; +} + + +/* This function writes the given TRE */ +NITFPRIV(NITF_BOOL) writeExtension(nitf_Writer * writer, + nitf_TRE * tre, nitf_Error * error) +{ + + nitf_Uint32 length; + + /* write the cetag and cel */ + if (!writeStringField(writer, tre->tag, + NITF_ETAG_SZ, SPACE, FILL_RIGHT, error)) + goto CATCH_ERROR; + + + length = tre->handler->getCurrentSize(tre, error); + if (length == -1) + goto CATCH_ERROR; + + if (!writeIntField(writer, length, NITF_EL_SZ, ZERO, FILL_LEFT, error)) + goto CATCH_ERROR; + + /* write the data, then free the buf */ + + if (!tre->handler->write(writer->output, tre, writer->record, error)) + goto CATCH_ERROR; + + return NITF_SUCCESS; + + /* Error */ +CATCH_ERROR: + return NITF_FAILURE; +} + + +/* This function writes the IGEOLO field */ +NITFPRIV(NITF_BOOL) writeCorners(nitf_Writer * writer, + nitf_ImageSubheader * subhdr, + nitf_Version fver, nitf_Error * error) +{ + if ((IS_NITF21(fver) && + (subhdr->NITF_ICORDS->raw[0] == 'U' || + subhdr->NITF_ICORDS->raw[0] == 'G' || + subhdr->NITF_ICORDS->raw[0] == 'N' || + subhdr->NITF_ICORDS->raw[0] == 'S' || + subhdr->NITF_ICORDS->raw[0] == 'D')) + || (IS_NITF20(fver) && subhdr->NITF_ICORDS->raw[0] != 'N')) + { + NITF_WRITE_VALUE(subhdr, NITF_IGEOLO, SPACE, FILL_RIGHT); + } + + return NITF_SUCCESS; + +CATCH_ERROR: + return NITF_FAILURE; +} + + +/* This function writes the given BandInfo */ +NITFPRIV(NITF_BOOL) writeBandInfo(nitf_Writer * writer, + nitf_BandInfo ** bandInfo, + nitf_Uint32 nbands, nitf_Error * error) +{ + nitf_Uint32 i; + nitf_Uint32 numLuts, bandEntriesPerLut; + + for (i = 0; i < nbands; ++i) + { + NITF_WRITE_VALUE(bandInfo[i], NITF_IREPBAND, SPACE, FILL_RIGHT); + NITF_WRITE_VALUE(bandInfo[i], NITF_ISUBCAT, SPACE, FILL_RIGHT); + NITF_WRITE_VALUE(bandInfo[i], NITF_IFC, SPACE, FILL_RIGHT); + NITF_WRITE_VALUE(bandInfo[i], NITF_IMFLT, SPACE, FILL_RIGHT); + NITF_WRITE_VALUE(bandInfo[i], NITF_NLUTS, ZERO, FILL_LEFT); + + NITF_TRY_GET_UINT32(bandInfo[i]->NITF_NLUTS, &numLuts, error); + if (numLuts > 0) + { + NITF_WRITE_VALUE(bandInfo[i], NITF_NELUT, ZERO, FILL_LEFT); + NITF_TRY_GET_UINT32(bandInfo[i]->NITF_NELUT, + &bandEntriesPerLut, error); + + if (!writeField(writer, (char *) bandInfo[i]->lut->table, + numLuts * bandEntriesPerLut, error)) + goto CATCH_ERROR; + } + } + + /* Normal completion */ + return NITF_SUCCESS; + + /* Error */ +CATCH_ERROR: + return NITF_FAILURE; +} + + +/* ------------------------------------------------------------------ */ +/* PUBLIC AREA */ +/* ------------------------------------------------------------------ */ + +NITFAPI(nitf_Writer *) nitf_Writer_construct(nitf_Error * error) +{ + /* Create the writer */ + nitf_Writer *writer = (nitf_Writer *) NITF_MALLOC(sizeof(nitf_Writer)); + + if (!writer) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + return NULL; + } + + /* NULL-initialize everything first */ + writer->imageWriters = NULL; + writer->graphicWriters = NULL; + writer->textWriters = NULL; + writer->dataExtensionWriters = NULL; + writer->output = NULL; + writer->ownOutput = 0; + writer->record = NULL; + writer->numImageWriters = 0; + writer->numTextWriters = 0; + writer->numGraphicWriters = 0; + writer->numDataExtensionWriters = 0; + + writer->warningList = nitf_List_construct(error); + if (!writer->warningList) + { + nitf_Writer_destruct(&writer); + return NULL; + } + + /* Return our results */ + return writer; +} + +/*! + * Destroy all of the Writers attached to this Writer + */ +NITFPRIV(void) nitf_Writer_destructWriters(nitf_Writer* writer) +{ + if (writer) + { + int i; + for (i = 0; i < (writer->numImageWriters) && writer->imageWriters; i++) + { + nitf_WriteHandler_destruct(&writer->imageWriters[i]); + } + + for (i = 0; i < (writer->numTextWriters) && writer->textWriters; i++) + { + nitf_WriteHandler_destruct(&writer->textWriters[i]); + } + + for (i = 0; i < (writer->numGraphicWriters) && writer->graphicWriters; i++) + { + nitf_WriteHandler_destruct(&writer->graphicWriters[i]); + } + + for (i = 0; i < (writer->numDataExtensionWriters) + && writer->dataExtensionWriters; i++) + { + nitf_WriteHandler_destruct(&writer->dataExtensionWriters[i]); + } + + if (writer->imageWriters) + { + NITF_FREE(writer->imageWriters); + } + if (writer->textWriters) + { + NITF_FREE(writer->textWriters); + } + if (writer->graphicWriters) + { + NITF_FREE(writer->graphicWriters); + } + if (writer->dataExtensionWriters) + { + NITF_FREE(writer->dataExtensionWriters); + } + + writer->imageWriters = NULL; + writer->textWriters = NULL; + writer->graphicWriters = NULL; + writer->dataExtensionWriters = NULL; + + writer->numImageWriters = 0; + writer->numTextWriters = 0; + writer->numGraphicWriters = 0; + writer->numDataExtensionWriters = 0; + } +} + + +NITFAPI(NITF_BOOL) nitf_Writer_prepareIO(nitf_Writer* writer, + nitf_Record* record, + nitf_IOInterface* io, + nitf_Error* error) +{ + nitf_Int32 i; + nitf_Int32 numImages; + nitf_Int32 numTexts; + nitf_Int32 numGraphics; + nitf_Int32 numDEs; + nitf_ListIterator iter; + + if (!writer) + { + nitf_Error_init(error, "NULL writer", NITF_CTXT, + NITF_ERR_INVALID_PARAMETER); + return NITF_FAILURE; + } + + /* Create overflow DE segments if needed */ + + if(!nitf_Record_unmergeTREs(record, error)) + return NITF_FAILURE; + + if (!nitf_Field_get + (record->header->numImages, &numImages, NITF_CONV_INT, + NITF_INT32_SZ, error)) + { + nitf_Error_init(error, "Could not retrieve number of images", + NITF_CTXT, NITF_ERR_INVALID_OBJECT); + return NITF_FAILURE; + } + if (numImages < 0 || numImages > 999) + { + nitf_Error_init(error, "Invalid number of images", NITF_CTXT, + NITF_ERR_INVALID_OBJECT); + return NITF_FAILURE; + } + + if (!nitf_Field_get + (record->header->numTexts, &numTexts, NITF_CONV_INT, + NITF_INT32_SZ, error)) + { + nitf_Error_init(error, "Could not retrieve number of texts", + NITF_CTXT, NITF_ERR_INVALID_OBJECT); + return NITF_FAILURE; + } + if (numTexts < 0 || numTexts > 999) + { + nitf_Error_init(error, "Invalid number of texts", NITF_CTXT, + NITF_ERR_INVALID_OBJECT); + return NITF_FAILURE; + } + + if (!nitf_Field_get + (record->header->numGraphics, &numGraphics, NITF_CONV_INT, + NITF_INT32_SZ, error)) + { + nitf_Error_init(error, "Could not retrieve number of graphics", + NITF_CTXT, NITF_ERR_INVALID_OBJECT); + return NITF_FAILURE; + } + if (numGraphics < 0 || numGraphics > 999) + { + nitf_Error_init(error, "Invalid number of graphics", NITF_CTXT, + NITF_ERR_INVALID_OBJECT); + return NITF_FAILURE; + } + + if (!nitf_Field_get + (record->header->numDataExtensions, &numDEs, NITF_CONV_INT, + NITF_INT32_SZ, error)) + { + nitf_Error_init(error, "Could not retrieve number of data extensions", + NITF_CTXT, NITF_ERR_INVALID_OBJECT); + return NITF_FAILURE; + } + if (numDEs < 0 || numDEs > 999) + { + nitf_Error_init(error, "Invalid number of data extensions", NITF_CTXT, + NITF_ERR_INVALID_OBJECT); + return NITF_FAILURE; + } + + /* first, destroy any writers attached to this Writer */ + nitf_Writer_destructWriters(writer); + + writer->record = record; + resetIOInterface(writer); + writer->output = io; + + /* setup image writers */ + if (numImages > 0) + { + /* must free the buf if it was already allocated */ + if (writer->imageWriters) + NITF_FREE(writer->imageWriters); + + writer->imageWriters = + (nitf_WriteHandler **) NITF_MALLOC(sizeof(nitf_WriteHandler *) * + numImages); + if (!writer->imageWriters) + { + nitf_Error_init(error, "Bad alloc for image writers", NITF_CTXT, + NITF_ERR_MEMORY); + return NITF_FAILURE; + } + writer->numImageWriters = numImages; + for (i = 0; i < numImages; i++) + { + nitf_ImageSegment *segment = NULL; + nitf_ImageSubheader *subheader = NULL; + nitf_Uint32 nbpp, nbands, xbands, nrows, ncols; + nitf_Uint64 length; + + /* first, set the writer to NULL */ + writer->imageWriters[i] = NULL; + + /* guard against an overflowing data length */ + iter = nitf_List_at(record->images, i); + segment = (nitf_ImageSegment*) nitf_ListIterator_get(&iter); + subheader = segment->subheader; + + /* calculate the length */ + NITF_TRY_GET_UINT32(subheader->numBitsPerPixel, &nbpp, error); + NITF_TRY_GET_UINT32(subheader->numImageBands, &nbands, error); + NITF_TRY_GET_UINT32(subheader->numMultispectralImageBands, &xbands, error); + NITF_TRY_GET_UINT32(subheader->numRows, &nrows, error); + NITF_TRY_GET_UINT32(subheader->numCols, &ncols, error); + + length = (nitf_Uint64)ncols * (nitf_Uint64)nrows * + NITF_NBPP_TO_BYTES(nbpp) * (nbands + xbands); + + if (length > NITF_MAX_IMAGE_LENGTH) + { + nitf_Error_init(error, "Image Length is too large", NITF_CTXT, + NITF_ERR_INVALID_OBJECT); + return NITF_FAILURE; + } + } + } + + /* setup text writers */ + if (numTexts > 0) + { + writer->textWriters = + (nitf_WriteHandler **) NITF_MALLOC(sizeof(nitf_WriteHandler *) * + numTexts); + if (!writer->textWriters) + { + nitf_Error_init(error, "Bad alloc for text writers", NITF_CTXT, + NITF_ERR_MEMORY); + return NITF_FAILURE; + } + writer->numTextWriters = numTexts; + for (i = 0; i < numTexts; i++) + { + writer->textWriters[i] = NULL; + } + } + + /* setup graphic writers */ + if (numGraphics > 0) + { + writer->graphicWriters = + (nitf_WriteHandler **) NITF_MALLOC(sizeof(nitf_WriteHandler *) * + numGraphics); + if (!writer->graphicWriters) + { + nitf_Error_init(error, "Bad alloc for graphic writers", NITF_CTXT, + NITF_ERR_MEMORY); + return NITF_FAILURE; + } + writer->numGraphicWriters = numGraphics; + for (i = 0; i < numGraphics; i++) + { + writer->graphicWriters[i] = NULL; + } + } + + if (numDEs > 0) + { + writer->dataExtensionWriters = + (nitf_WriteHandler **) NITF_MALLOC(sizeof(nitf_WriteHandler *) * + numDEs); + if (!writer->dataExtensionWriters) + { + nitf_Error_init(error, "Bad alloc for data extension writers", + NITF_CTXT, NITF_ERR_MEMORY); + return NITF_FAILURE; + } + writer->numDataExtensionWriters = numDEs; + for (i = 0; i < numDEs; i++) + { + writer->dataExtensionWriters[i] = NULL; + } + } + + return NITF_SUCCESS; + + CATCH_ERROR: + return NITF_FAILURE; + +} + +NITFAPI(NITF_BOOL) nitf_Writer_prepare(nitf_Writer * writer, + nitf_Record * record, + nitf_IOHandle ioHandle, + nitf_Error * error) +{ + NITF_BOOL rc; + nitf_IOInterface* io = nitf_IOHandleAdapter_construct(ioHandle, + NRT_ACCESS_WRITEONLY, + error); + if (!io) + return NITF_FAILURE; + + rc = nitf_Writer_prepareIO(writer, record, io, error); + writer->ownOutput = 1; + return rc; +} + + +NITFAPI(void) nitf_Writer_destruct(nitf_Writer ** writer) +{ + /* If the writer has already been destructed, or was never */ + /* Inited, dont dump core */ + if (*writer) + { + nitf_Writer_destructWriters(*writer); + + if ((*writer)->warningList) + { + nitf_List_destruct(&(*writer)->warningList); + } + + resetIOInterface(*writer); + NITF_FREE(*writer); + *writer = NULL; + } +} + + +NITFPRIV(NITF_BOOL) writeHeader(nitf_Writer * writer, + nitf_Off * fileLenOff, + nitf_Uint32 * hdrLen, + nitf_Error * error) +{ + nitf_Uint32 numImages, numGraphics, numLabels; + nitf_Uint32 numTexts, numDES, numRES; + nitf_Uint32 udhdl, udhofl, xhdl, xhdlofl; + nitf_Version fver; + char buf[256]; /* temp buf */ + + fver = nitf_Record_getVersion(writer->record); + + /* start writing */ + NITF_WRITE_VALUE(writer->record->header, NITF_FHDR, SPACE, FILL_RIGHT); + NITF_WRITE_VALUE(writer->record->header, NITF_FVER, ZERO, FILL_LEFT); + NITF_WRITE_VALUE(writer->record->header, NITF_CLEVEL, ZERO, FILL_LEFT); + NITF_WRITE_VALUE(writer->record->header, NITF_STYPE, SPACE, FILL_RIGHT); + NITF_WRITE_VALUE(writer->record->header, NITF_OSTAID, SPACE, FILL_RIGHT); + NITF_WRITE_VALUE(writer->record->header, NITF_FDT, SPACE, FILL_RIGHT); + NITF_WRITE_VALUE(writer->record->header, NITF_FTITLE, SPACE, FILL_RIGHT); + NITF_WRITE_VALUE(writer->record->header, NITF_FSCLAS, SPACE, FILL_RIGHT); + + if (IS_NITF20(fver)) + { + if (!write20FileSecurity(writer, + writer->record->header->securityGroup, error)) + goto CATCH_ERROR; + } + else if (IS_NITF21(fver)) + { + if (!write21FileSecurity(writer, + writer->record->header->securityGroup, error)) + goto CATCH_ERROR; + } + else + { + nitf_Error_init(error, "Invalid NITF Version", + NITF_CTXT, NITF_ERR_UNK); + goto CATCH_ERROR; + } + + NITF_WRITE_VALUE(writer->record->header, NITF_FSCOP, ZERO, FILL_LEFT); + NITF_WRITE_VALUE(writer->record->header, NITF_FSCPYS, ZERO, FILL_LEFT); + NITF_WRITE_VALUE(writer->record->header, NITF_ENCRYP, ZERO, FILL_LEFT); + + if (IS_NITF20(fver)) + { + if (!writeValue(writer, writer->record->header->NITF_ONAME, + NITF_FBKGC_SZ + NITF_ONAME_SZ, SPACE, FILL_RIGHT, error)) + goto CATCH_ERROR; + } + else + { + NITF_WRITE_VALUE(writer->record->header, NITF_FBKGC, 0, FILL_LEFT); + NITF_WRITE_VALUE(writer->record->header, NITF_ONAME, SPACE, FILL_RIGHT); + } + + NITF_WRITE_VALUE(writer->record->header, NITF_OPHONE, SPACE, FILL_RIGHT); + + *fileLenOff = nitf_IOInterface_tell(writer->output, error); + if (!NITF_IO_SUCCESS(*fileLenOff)) + goto CATCH_ERROR; + + NITF_WRITE_VALUE(writer->record->header, NITF_FL, ZERO, FILL_LEFT); + NITF_WRITE_VALUE(writer->record->header, NITF_HL, ZERO, FILL_LEFT); + + /* Write component info */ + NITF_TRY_GET_UINT32(writer->record->header->numImages, + &numImages, error); + NITF_TRY_GET_UINT32(writer->record->header->numGraphics, + &numGraphics, error); + NITF_TRY_GET_UINT32(writer->record->header->numLabels, + &numLabels, error); + NITF_TRY_GET_UINT32(writer->record->header->numTexts, + &numTexts, error); + NITF_TRY_GET_UINT32(writer->record->header->numDataExtensions, + &numDES, error); + NITF_TRY_GET_UINT32(writer->record->header->numReservedExtensions, + &numRES, error); + + NITF_WRITE_IMAGE_INFO(writer->record->header->imageInfo, numImages); + + /* + Do not try to write anything but images, graphics, texts and DEs for now + */ + numLabels = 0; + numRES = 0; + + NITF_WRITE_GRAPHICS_INFO(writer->record->header->graphicInfo, + numGraphics); + + NITF_WRITE_LABEL_INFO(writer->record->header->labelInfo, numLabels); + + NITF_WRITE_TEXT_INFO(writer->record->header->textInfo, numTexts); + + NITF_WRITE_DATA_EXT_INFO(writer->record->header->dataExtensionInfo, + numDES); + + NITF_WRITE_RES_EXT_INFO(writer->record->header->reservedExtensionInfo, + numRES); + + NITF_TRY_GET_UINT32(writer->record->header->userDefinedHeaderLength, + &udhdl, error); + NITF_TRY_GET_UINT32(writer->record->header->userDefinedOverflow, + &udhofl, error); + NITF_TRY_GET_UINT32(writer->record->header->extendedHeaderLength, + &xhdl, error); + NITF_TRY_GET_UINT32(writer->record->header->extendedHeaderOverflow, + &xhdlofl, error); + + NITF_WRITE_USER_HDR_INFO(writer->record->header->userDefinedSection, + &udhdl, &udhofl); + NITF_WRITE_EXT_HDR_INFO(writer->record->header->extendedSection, + &xhdl, &xhdlofl); + + /* just to be nice, let's set these values in the record */ + NITF_SNPRINTF(buf, 256, "%.*d", NITF_UDHDL_SZ, udhdl); + nitf_Field_setRawData(writer->record->header->userDefinedHeaderLength, + buf, NITF_UDHDL_SZ, error); + + NITF_SNPRINTF(buf, 256, "%.*d", NITF_UDHOFL_SZ, udhofl); + nitf_Field_setRawData(writer->record->header->userDefinedOverflow, + buf, NITF_UDHOFL_SZ, error); + + NITF_SNPRINTF(buf, 256, "%.*d", NITF_XHDL_SZ, xhdl); + nitf_Field_setRawData(writer->record->header->extendedHeaderLength, + buf, NITF_XHDL_SZ, error); + + NITF_SNPRINTF(buf, 256, "%.*d", NITF_XHDLOFL_SZ, xhdlofl); + nitf_Field_setRawData(writer->record->header->extendedHeaderOverflow, + buf, NITF_XHDLOFL_SZ, error); + + /* Get the header length */ + *hdrLen = nitf_IOInterface_tell(writer->output, error); + if (!NITF_IO_SUCCESS(*hdrLen)) + goto CATCH_ERROR; + + /* Normal completion */ + return NITF_SUCCESS; + + /* Error */ +CATCH_ERROR: + return NITF_FAILURE; +} + + +NITFPRIV(NITF_BOOL) +nitf_Writer_writeImageSubheader(nitf_Writer * writer, + nitf_ImageSubheader *subhdr, + nitf_Version fver, + nitf_Off *comratOff, + nitf_Error * error) +{ + nitf_Uint32 bands; + nitf_Uint32 i; + nitf_Uint32 numComments; + nitf_Uint32 udidl, udofl, ixshdl, ixsofl; + nitf_ListIterator iter, end; + + NITF_WRITE_VALUE(subhdr, NITF_IM, SPACE, FILL_RIGHT); + NITF_WRITE_VALUE(subhdr, NITF_IID1, SPACE, FILL_RIGHT); + NITF_WRITE_VALUE(subhdr, NITF_IDATIM, SPACE, FILL_RIGHT); + NITF_WRITE_VALUE(subhdr, NITF_TGTID, SPACE, FILL_RIGHT); + NITF_WRITE_VALUE(subhdr, NITF_IID2, SPACE, FILL_RIGHT); + NITF_WRITE_VALUE(subhdr, NITF_ISCLAS, SPACE, FILL_RIGHT); + + if (IS_NITF20(fver)) + { + if (!write20FileSecurity(writer, subhdr->securityGroup, error)) + goto CATCH_ERROR; + } + else if (IS_NITF21(fver)) + { + if (!write21FileSecurity(writer, subhdr->securityGroup, error)) + goto CATCH_ERROR; + } + else + { + /* !!!we should check this earlier, not here */ + nitf_Error_init(error, "Invalid NITF Version", + NITF_CTXT, NITF_ERR_UNK); + goto CATCH_ERROR; + } + + NITF_WRITE_VALUE(subhdr, NITF_ENCRYP, ZERO, FILL_LEFT); + NITF_WRITE_VALUE(subhdr, NITF_ISORCE, SPACE, FILL_RIGHT); + + NITF_WRITE_VALUE(subhdr, NITF_NROWS, ZERO, FILL_LEFT); + NITF_WRITE_VALUE(subhdr, NITF_NCOLS, ZERO, FILL_LEFT); + + NITF_WRITE_VALUE(subhdr, NITF_PVTYPE, SPACE, FILL_RIGHT); + NITF_WRITE_VALUE(subhdr, NITF_IREP, SPACE, FILL_RIGHT); + NITF_WRITE_VALUE(subhdr, NITF_ICAT, SPACE, FILL_RIGHT); + + NITF_WRITE_VALUE(subhdr, NITF_ABPP, ZERO, FILL_LEFT); + NITF_WRITE_VALUE(subhdr, NITF_PJUST, SPACE, FILL_RIGHT); + + NITF_WRITE_VALUE(subhdr, NITF_ICORDS, SPACE, FILL_RIGHT); + + if (!writeCorners(writer, subhdr, fver, error)) + goto CATCH_ERROR; + + /* image comments */ + NITF_WRITE_VALUE(subhdr, NITF_NICOM, ZERO, FILL_LEFT); + NITF_TRY_GET_UINT32(subhdr->numImageComments, &numComments, error); + + /* loop through and write the comments */ + iter = nitf_List_begin(subhdr->imageComments); + end = nitf_List_end(subhdr->imageComments); + i = 0; + while (nitf_ListIterator_notEqualTo(&iter, &end) && i < numComments) + { + nitf_Field* commentField = (nitf_Field*) nitf_ListIterator_get(&iter); + if (!writeStringField(writer, commentField->raw, NITF_ICOM_SZ, + SPACE, FILL_RIGHT, error)) + goto CATCH_ERROR; + nitf_ListIterator_increment(&iter); + ++i; + } + + NITF_WRITE_VALUE(subhdr, NITF_IC, SPACE, FILL_RIGHT); + + if (strncmp(subhdr->imageCompression->raw, "NC", 2) != 0 + && strncmp(subhdr->imageCompression->raw, "NM", 2) != 0) + { + *comratOff = nitf_IOInterface_tell(writer->output, error); + NITF_WRITE_VALUE(subhdr, NITF_COMRAT, SPACE, FILL_RIGHT); + } + + /* deal with bands */ + NITF_WRITE_VALUE(subhdr, NITF_NBANDS, ZERO, FILL_LEFT); + NITF_TRY_GET_UINT32(subhdr->numImageBands, &bands, error); + + if ((!bands) && IS_NITF21(fver)) + { + NITF_WRITE_VALUE(subhdr, NITF_XBANDS, ZERO, FILL_LEFT); + NITF_TRY_GET_UINT32(subhdr->numMultispectralImageBands, &bands, + error); + } + if (!writeBandInfo(writer, subhdr->bandInfo, bands, error)) + goto CATCH_ERROR; + + NITF_WRITE_VALUE(subhdr, NITF_ISYNC, ZERO, FILL_LEFT); + NITF_WRITE_VALUE(subhdr, NITF_IMODE, SPACE, FILL_RIGHT); + + NITF_WRITE_VALUE(subhdr, NITF_NBPR, ZERO, FILL_LEFT); + NITF_WRITE_VALUE(subhdr, NITF_NBPC, ZERO, FILL_LEFT); + NITF_WRITE_VALUE(subhdr, NITF_NPPBH, ZERO, FILL_LEFT); + NITF_WRITE_VALUE(subhdr, NITF_NPPBV, ZERO, FILL_LEFT); + NITF_WRITE_VALUE(subhdr, NITF_NBPP, ZERO, FILL_LEFT); + + NITF_WRITE_VALUE(subhdr, NITF_IDLVL, ZERO, FILL_LEFT); + NITF_WRITE_VALUE(subhdr, NITF_IALVL, ZERO, FILL_LEFT); + NITF_WRITE_VALUE(subhdr, NITF_ILOC, ZERO, FILL_LEFT); + NITF_WRITE_VALUE(subhdr, NITF_IMAG, SPACE, FILL_RIGHT); + + /* deal with extensions */ + NITF_TRY_GET_UINT32(subhdr->NITF_UDIDL, &udidl, error); + NITF_TRY_GET_UINT32(subhdr->NITF_UDOFL, &udofl, error); + NITF_TRY_GET_UINT32(subhdr->NITF_IXSHDL, &ixshdl, error); + NITF_TRY_GET_UINT32(subhdr->NITF_IXSOFL, &ixsofl, error); + + NITF_WRITE_USER_HDR_INFO(subhdr->userDefinedSection, &udidl, &udofl); + NITF_WRITE_EXT_HDR_INFO(subhdr->extendedSection, &ixshdl, &ixsofl); + + /* Normal completion */ + return NITF_SUCCESS; + + /* Error */ +CATCH_ERROR: + return NITF_FAILURE; +} + + +NITFPRIV(NITF_BOOL) writeGraphicSubheader(nitf_Writer * writer, + nitf_GraphicSubheader * subhdr, + nitf_Version fver, + nitf_Error * error) +{ + nitf_Uint32 sxshdl, sxsofl; + + NITF_WRITE_VALUE(subhdr, NITF_SY, SPACE, FILL_RIGHT); + NITF_WRITE_VALUE(subhdr, NITF_SID, SPACE, FILL_RIGHT); + NITF_WRITE_VALUE(subhdr, NITF_SNAME, SPACE, FILL_RIGHT); + NITF_WRITE_VALUE(subhdr, NITF_SSCLAS, SPACE, FILL_RIGHT); + + if (IS_NITF20(fver)) + { + if (!write20FileSecurity(writer, subhdr->securityGroup, error)) + goto CATCH_ERROR; + } + else if (IS_NITF21(fver)) + { + if (!write21FileSecurity(writer, subhdr->securityGroup, error)) + goto CATCH_ERROR; + } + else + { + /* !!!we should check this earlier, not here */ + nitf_Error_init(error, "Invalid NITF Version", + NITF_CTXT, NITF_ERR_UNK); + goto CATCH_ERROR; + } + + NITF_WRITE_VALUE(subhdr, NITF_ENCRYP, ZERO, FILL_LEFT); + NITF_WRITE_VALUE(subhdr, NITF_SFMT, SPACE, FILL_RIGHT); + NITF_WRITE_VALUE(subhdr, NITF_SSTRUCT, SPACE, FILL_RIGHT); + NITF_WRITE_VALUE(subhdr, NITF_SDLVL, SPACE, FILL_RIGHT); + NITF_WRITE_VALUE(subhdr, NITF_SALVL, SPACE, FILL_RIGHT); + NITF_WRITE_VALUE(subhdr, NITF_SLOC, SPACE, FILL_RIGHT); + NITF_WRITE_VALUE(subhdr, NITF_SBND1, SPACE, FILL_RIGHT); + NITF_WRITE_VALUE(subhdr, NITF_SCOLOR, SPACE, FILL_RIGHT); + NITF_WRITE_VALUE(subhdr, NITF_SBND2, SPACE, FILL_RIGHT); + NITF_WRITE_VALUE(subhdr, NITF_SRES2, SPACE, FILL_RIGHT); + + /* deal with extensions */ + NITF_TRY_GET_UINT32(subhdr->extendedHeaderLength, &sxshdl, error); + NITF_TRY_GET_UINT32(subhdr->extendedHeaderOverflow, &sxsofl, error); + NITF_WRITE_EXT_HDR_INFO(subhdr->extendedSection, &sxshdl, &sxsofl); + + return NITF_SUCCESS; + +CATCH_ERROR: + return NITF_FAILURE; +} + +NITFPRIV(NITF_BOOL) writeTextSubheader(nitf_Writer * writer, + nitf_TextSubheader * subhdr, + nitf_Version fver, + nitf_Error * error) +{ + nitf_Uint32 txshdl, txsofl; + + NITF_WRITE_VALUE(subhdr, NITF_TE, SPACE, FILL_RIGHT); + NITF_WRITE_VALUE(subhdr, NITF_TEXTID, SPACE, FILL_RIGHT); + NITF_WRITE_VALUE(subhdr, NITF_TXTALVL, SPACE, FILL_RIGHT); + NITF_WRITE_VALUE(subhdr, NITF_TXTDT, SPACE, FILL_RIGHT); + NITF_WRITE_VALUE(subhdr, NITF_TXTITL, SPACE, FILL_RIGHT); + NITF_WRITE_VALUE(subhdr, NITF_TSCLAS, SPACE, FILL_RIGHT); + + if (IS_NITF20(fver)) + { + if (!write20FileSecurity(writer, subhdr->securityGroup, error)) + goto CATCH_ERROR; + } + else if (IS_NITF21(fver)) + { + if (!write21FileSecurity(writer, subhdr->securityGroup, error)) + goto CATCH_ERROR; + } + else + { + /* !!!we should check this earlier, not here */ + nitf_Error_init(error, "Invalid NITF Version", + NITF_CTXT, NITF_ERR_UNK); + goto CATCH_ERROR; + } + + NITF_WRITE_VALUE(subhdr, NITF_ENCRYP, ZERO, FILL_LEFT); + NITF_WRITE_VALUE(subhdr, NITF_TXTFMT, SPACE, FILL_RIGHT); + + /* deal with extensions */ + NITF_TRY_GET_UINT32(subhdr->extendedHeaderLength, &txshdl, error); + NITF_TRY_GET_UINT32(subhdr->extendedHeaderOverflow, &txsofl, error); + NITF_WRITE_EXT_HDR_INFO(subhdr->extendedSection, &txshdl, &txsofl); + + return NITF_SUCCESS; + +CATCH_ERROR: + return NITF_FAILURE; +} + + +NITFPRIV(NITF_BOOL) writeDESubheader(nitf_Writer * writer, + nitf_DESubheader * subhdr, + nitf_Uint32 *userSublen, + nitf_Version fver, + nitf_Error * error) +{ + nitf_Uint32 subLen; + + char* des_data = NULL; + + /* DE type ID */ + char desID[NITF_DESTAG_SZ + 1]; + + /* Get the desID */ + if (!nitf_Field_get(subhdr->typeID, + (NITF_DATA *) desID, NITF_CONV_STRING, + NITF_DESTAG_SZ + 1, error)) + goto CATCH_ERROR; + + nitf_Field_trimString(desID); + + NITF_WRITE_VALUE(subhdr, NITF_DE, SPACE, FILL_RIGHT); + NITF_WRITE_VALUE(subhdr, NITF_DESTAG, SPACE, FILL_RIGHT); + NITF_WRITE_VALUE(subhdr, NITF_DESVER, SPACE, FILL_RIGHT); + NITF_WRITE_VALUE(subhdr, NITF_DESCLAS, SPACE, FILL_RIGHT); + + if (IS_NITF20(fver)) + { + if (!write20FileSecurity(writer, subhdr->securityGroup, error)) + goto CATCH_ERROR; + } + else if (IS_NITF21(fver)) + { + if (!write21FileSecurity(writer, subhdr->securityGroup, error)) + goto CATCH_ERROR; + } + else + { + /* !!!we should check this earlier, not here */ + nitf_Error_init(error, "Invalid NITF Version", + NITF_CTXT, NITF_ERR_UNK); + goto CATCH_ERROR; + } + + if (strcmp(desID, "TRE_OVERFLOW") == 0) + { + NITF_WRITE_VALUE(subhdr, NITF_DESOFLW, SPACE, FILL_RIGHT); + NITF_WRITE_VALUE(subhdr, NITF_DESITEM, SPACE, FILL_RIGHT); + } + + if (subhdr->subheaderFields) + { + subLen = subhdr->subheaderFields->handler->getCurrentSize(subhdr->subheaderFields, error); + if (subLen < 0) + goto CATCH_ERROR; + } + else + subLen = 0; + + nitf_Field_setUint32(subhdr->NITF_DESSHL, subLen, error); + NITF_WRITE_VALUE(subhdr, NITF_DESSHL, ZERO, FILL_LEFT); + + *userSublen = subLen; + + if (subLen > 0) + { + if (!subhdr->subheaderFields->handler->write(writer->output, + subhdr->subheaderFields, + writer->record, + error)) + goto CATCH_ERROR; + } + + if (des_data) + NITF_FREE(des_data); + + return NITF_SUCCESS; + +CATCH_ERROR: + if (des_data) + NITF_FREE(des_data); + + return NITF_FAILURE; +} + + +/* For now, we won't support writing RES +NITFPRIV(NITF_BOOL) writeRESubheader(nitf_Writer * writer, + nitf_RESubheader * subhdr, + nitf_Version fver, nitf_Error * error) +{ + nitf_Uint32 subLen; + + NITF_WRITE_VALUE(subhdr, NITF_RE, SPACE, FILL_RIGHT); + NITF_WRITE_VALUE(subhdr, NITF_RESTAG, SPACE, FILL_RIGHT); + NITF_WRITE_VALUE(subhdr, NITF_RESVER, SPACE, FILL_RIGHT); + NITF_WRITE_VALUE(subhdr, NITF_RESCLAS, SPACE, FILL_RIGHT); + + if (IS_NITF20(fver)) + { + if (!write20FileSecurity(writer, subhdr->securityGroup, error)) + goto CATCH_ERROR; + } + else if (IS_NITF21(fver)) + { + if (!write21FileSecurity(writer, subhdr->securityGroup, error)) + goto CATCH_ERROR; + } + else + { + nitf_Error_init(error, "Invalid NITF Version", + NITF_CTXT, NITF_ERR_UNK); + goto CATCH_ERROR; + } + + NITF_WRITE_VALUE(subhdr, NITF_RESSHL, SPACE, FILL_RIGHT); + NITF_TRY_GET_UINT32(subhdr->subheaderFieldsLength, &subLen, error); + if (subLen > 0) + { + if (!writeField(writer, subhdr->subheaderFields, subLen, error)) + goto CATCH_ERROR; + } + + + nitf_Error_init(error, + "RES Error... TODO: Change code in readRESubheader", + NITF_CTXT, NITF_ERR_UNK); + goto CATCH_ERROR; + + return NITF_SUCCESS; + +CATCH_ERROR: + return NITF_FAILURE; +} +*/ + +NITFPRIV(NITF_BOOL) writeImage(nitf_WriteHandler * imageWriter, + nitf_IOInterface* output, + nitf_Error * error) +{ + if (!imageWriter) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_INVALID_PARAMETER, + "Trying to use uninitialized image writer. Write failed."); + goto CATCH_ERROR; + } + return (*imageWriter->iface->write)(imageWriter->data, output, error); + +CATCH_ERROR: + return NITF_FAILURE; +} + + +NITFPRIV(NITF_BOOL) writeText(nitf_WriteHandler *textWriter, + nitf_IOInterface* output, + nitf_Error * error) +{ + if (!textWriter) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_INVALID_PARAMETER, + "Trying to use uninitialized Text Writer. Write failed."); + goto CATCH_ERROR; + } + return (*textWriter->iface->write)(textWriter->data, output, error); +CATCH_ERROR: + return NITF_FAILURE; +} + + +NITFPRIV(NITF_BOOL) writeGraphic(nitf_WriteHandler * graphicWriter, + nitf_IOInterface* output, + nitf_Error * error) +{ + if (!graphicWriter) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_INVALID_PARAMETER, + "Trying to use uninitialized Graphic SegmentWriter. Write failed."); + goto CATCH_ERROR; + } + return (*graphicWriter->iface->write)(graphicWriter->data, output, error); +CATCH_ERROR: + return NITF_FAILURE; +} + +NITFPRIV(NITF_BOOL) writeDE(nitf_Writer* writer, + nitf_WriteHandler * deWriter, + nitf_DESubheader *subheader, + nitf_IOInterface* output, + nitf_Error *error) +{ + /* DESID for overflow check */ + char desid[NITF_DESTAG_SZ+1]; + + /* Check for overflow segment */ + if(!nitf_Field_get(subheader->NITF_DESTAG,(NITF_DATA *) desid, + NITF_CONV_STRING,NITF_DESTAG_SZ+1, error)) + { + nitf_Error_init(error, + "Could not retrieve DE segment id", + NITF_CTXT, NITF_ERR_INVALID_OBJECT); + return NITF_FAILURE; + } + + nitf_Field_trimString(desid); + if ((strcmp(desid, "TRE_OVERFLOW") == 0) || + (strcmp(desid, "Registered Extensions") == 0) || + (strcmp(desid, "Controlled Extensions") == 0)) + { + /* TRE iterator */ + nitf_ExtensionsIterator iter; + + /* End iterator */ + nitf_ExtensionsIterator end; + nitf_TRE *tre = NULL; + + iter = nitf_Extensions_begin(subheader->userDefinedSection); + end = nitf_Extensions_end(subheader->userDefinedSection); + + while (nitf_ExtensionsIterator_notEqualTo(&iter, &end)) + { + tre = (nitf_TRE *) nitf_ExtensionsIterator_get(&iter); + + if(!writeExtension(writer, tre, error)) + goto CATCH_ERROR; + + nitf_ExtensionsIterator_increment(&iter); + } + return NITF_SUCCESS; + } + else + { + if (!deWriter) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_INVALID_PARAMETER, + "Trying to use uninitialized DE SegmentWriter. Write failed."); + goto CATCH_ERROR; + } + return (*deWriter->iface->write)(deWriter->data, output, error); + } + + CATCH_ERROR: + return NITF_FAILURE; +} + +NITFAPI(NITF_BOOL) nitf_Writer_write(nitf_Writer * writer, + nitf_Error * error) +{ + nitf_ListIterator iter; + nitf_ListIterator end; + + /* Offset to the file length field */ + nitf_Off fileLenOff; + + /* The final file length */ + nitf_Off fileLen; + + /* Length of teh file header */ + nitf_Uint32 hdrLen; + nitf_Uint32 i = 0; + int skipBytes = 0; + nitf_Version fver; + + /* Number of images */ + nitf_Uint32 numImgs = 0; + + /* Lengths of image subheaders */ + nitf_Off *imageSubLens = NULL; + + /* Lengths of image data */ + nitf_Off *imageDataLens = NULL; + + /* Number of texts */ + nitf_Uint32 numTexts = 0; + + /* Lengths of text subheaders */ + nitf_Off *textSubLens = NULL; + + /* Lengths of text data */ + nitf_Off *textDataLens = NULL; + + /* Number of graphics */ + nitf_Uint32 numGraphics = 0; + + /* Lengths of graphic subheaders */ + nitf_Off *graphicSubLens = NULL; + + /* Lengths of graphic data */ + nitf_Off *graphicDataLens = NULL; + + /* Number of data extensions */ + nitf_Uint32 numDEs = 0; + + /* Lengths of data extension subheaders */ + nitf_Off *deSubLens = NULL; + + /* Lengths of data extensions data */ + nitf_Off *deDataLens = NULL; + + /* Start file size */ + nitf_Off startSize; + + /* End file size */ + nitf_Off endSize; + + nitf_FileHeader* header = writer->record->header; + + if (!writeHeader(writer, &fileLenOff, &hdrLen, error)) + return NITF_FAILURE; + + fver = nitf_Record_getVersion(writer->record); + + /*******************************************************************/ + /* START DEALING WITH IMAGES */ + /*******************************************************************/ + if (!nitf_Field_get(header->numImages, &numImgs, + NITF_CONV_INT, NITF_INT32_SZ, error)) + { + nitf_Error_init(error, "Could not retrieve number of images", + NITF_CTXT, NITF_ERR_INVALID_OBJECT); + return NITF_FAILURE; + } + + imageSubLens = NULL; /* Void uninitialized variable warning */ + imageDataLens = NULL; /* Void uninitialized variable warning */ + if (numImgs != 0) + { + imageSubLens = (nitf_Off *) NITF_MALLOC(numImgs * sizeof(nitf_Off)); + if (!imageSubLens) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + return NITF_FAILURE; + } + imageDataLens = (nitf_Off *) NITF_MALLOC(numImgs * sizeof(nitf_Off)); + if (!imageDataLens) + { + NITF_FREE(imageSubLens); + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + return NITF_FAILURE; + } + + iter = nitf_List_begin(writer->record->images); + end = nitf_List_end(writer->record->images); + + startSize = nitf_IOInterface_getSize(writer->output, error); + if (!NITF_IO_SUCCESS(startSize)) + { + NITF_FREE(imageSubLens); + NITF_FREE(imageDataLens); + return NITF_FAILURE; + } + i = 0; /* reset the counter */ + while (nitf_ListIterator_notEqualTo(&iter, &end)) + { + nitf_Off comratOff = 0; + nitf_ImageSegment *segment = NULL; + + segment = (nitf_ImageSegment *) nitf_ListIterator_get(&iter); + if (!nitf_Writer_writeImageSubheader(writer, segment->subheader, + fver, &comratOff, error)) + { + NITF_FREE(imageSubLens); + NITF_FREE(imageDataLens); + return NITF_FAILURE; + } + endSize = nitf_IOInterface_getSize(writer->output, error); + if (!NITF_IO_SUCCESS(endSize)) + { + NITF_FREE(imageSubLens); + NITF_FREE(imageDataLens); + return NITF_FAILURE; + } + imageSubLens[i] = endSize - startSize; + startSize = endSize; + + /* TODO - we need to check to make sure the imageWriter exists */ + if (!writeImage(writer->imageWriters[i], + writer->output, error)) + { + NITF_FREE(imageSubLens); + NITF_FREE(imageDataLens); + return NITF_FAILURE; + } + + endSize = nitf_IOInterface_getSize(writer->output, error); + if (!NITF_IO_SUCCESS(endSize)) + { + NITF_FREE(imageSubLens); + NITF_FREE(imageDataLens); + return NITF_FAILURE; + } + imageDataLens[i] = endSize - startSize; + startSize = endSize; + + /* the comrat field may have changed during the write, so we + * need to update if it is compressed + */ + if (comratOff > 0) + { + nitf_IOInterface_seek(writer->output, comratOff, NITF_SEEK_SET, + error); + NITF_WRITE_VALUE(segment->subheader, NITF_COMRAT, SPACE, + FILL_RIGHT); + nitf_IOInterface_seek(writer->output, endSize, NITF_SEEK_SET, + error); + } + + /* + TODO - should we check the data length written + against NITF_MAX_IMAGE_LENGTH? + + DP: Should not have to, we did it during the prepare + + */ + + nitf_ListIterator_increment(&iter); + ++i; + } + } + + /*******************************************************************/ + /* START DEALING WITH GRAPHICS */ + /*******************************************************************/ + if (!nitf_Field_get(header->numGraphics, &numGraphics, + NITF_CONV_INT, NITF_INT32_SZ, error)) + { + nitf_Error_init(error, "Could not retrieve number of Graphics", + NITF_CTXT, NITF_ERR_INVALID_OBJECT); + return NITF_FAILURE; + } + + /* TODO - WE NEED TO CHECK IF A WRITER IS SETUP FOR EACH SEGMENT */ + /* IF NOT, WE SHOULD NOT WRITE THE SEGMENT AT ALL, OR SET THE DATA TO 0 */ + + graphicSubLens = NULL; + graphicDataLens = NULL; + + if (numGraphics != 0) + { + graphicSubLens = (nitf_Off *) NITF_MALLOC(numGraphics * sizeof(nitf_Off)); + if (!graphicSubLens) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + return NITF_FAILURE; + } + graphicDataLens = (nitf_Off *) NITF_MALLOC(numGraphics * sizeof(nitf_Off)); + if (!graphicDataLens) + { + NITF_FREE(graphicSubLens); + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + return NITF_FAILURE; + } + + iter = nitf_List_begin(writer->record->graphics); + end = nitf_List_end(writer->record->graphics); + + startSize = nitf_IOInterface_getSize(writer->output, error); + if (!NITF_IO_SUCCESS(startSize)) + { + NITF_FREE(graphicSubLens); + NITF_FREE(graphicDataLens); + return NITF_FAILURE; + } + i = 0; /* reset the counter */ + while (nitf_ListIterator_notEqualTo(&iter, &end)) + { + nitf_GraphicSegment *segment = + (nitf_GraphicSegment *) nitf_ListIterator_get(&iter); + if (!writeGraphicSubheader(writer, + segment->subheader, fver, + error)) + { + NITF_FREE(graphicSubLens); + NITF_FREE(graphicDataLens); + return NITF_FAILURE; + } + endSize = nitf_IOInterface_getSize(writer->output, error); + if (!NITF_IO_SUCCESS(endSize)) + { + NITF_FREE(graphicSubLens); + NITF_FREE(graphicDataLens); + return NITF_FAILURE; + } + graphicSubLens[i] = endSize - startSize; + startSize = endSize; + /* TODO - we need to check to make sure the imageWriter exists */ + if (!writeGraphic(writer->graphicWriters[i], + writer->output, error)) + { + NITF_FREE(graphicSubLens); + NITF_FREE(graphicDataLens); + return NITF_FAILURE; + } + endSize = nitf_IOInterface_getSize(writer->output, error); + if (!NITF_IO_SUCCESS(endSize)) + { + NITF_FREE(graphicSubLens); + NITF_FREE(graphicDataLens); + return NITF_FAILURE; + } + graphicDataLens[i] = endSize - startSize; + startSize = endSize; + + nitf_ListIterator_increment(&iter); + ++i; + } + } + + /*******************************************************************/ + /* START DEALING WITH TEXTS */ + /*******************************************************************/ + if (!nitf_Field_get(header->numTexts, &numTexts, + NITF_CONV_INT, NITF_INT32_SZ, error)) + { + nitf_Error_init(error, "Could not retrieve number of texts", + NITF_CTXT, NITF_ERR_INVALID_OBJECT); + return NITF_FAILURE; + } + + /* TODO - WE NEED TO CHECK IF A WRITER IS SETUP FOR EACH SEGMENT */ + /* IF NOT, WE SHOULD NOT WRITE THE SEGMENT AT ALL, OR SET THE DATA TO 0 */ + + textSubLens = NULL; + textDataLens = NULL; + if (numTexts != 0) + { + textSubLens = (nitf_Off *) NITF_MALLOC(numTexts * sizeof(nitf_Off)); + if (!textSubLens) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + return NITF_FAILURE; + } + textDataLens = (nitf_Off *) NITF_MALLOC(numTexts * sizeof(nitf_Off)); + if (!textDataLens) + { + NITF_FREE(textSubLens); + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + return NITF_FAILURE; + } + + iter = nitf_List_begin(writer->record->texts); + end = nitf_List_end(writer->record->texts); + + startSize = nitf_IOInterface_getSize(writer->output, error); + if (!NITF_IO_SUCCESS(startSize)) + { + NITF_FREE(textSubLens); + NITF_FREE(textDataLens); + return NITF_FAILURE; + } + i = 0; /* reset the counter */ + while (nitf_ListIterator_notEqualTo(&iter, &end)) + { + nitf_TextSegment *segment = + (nitf_TextSegment *) nitf_ListIterator_get(&iter); + if (!writeTextSubheader(writer, + segment->subheader, fver, + error)) + { + NITF_FREE(textSubLens); + NITF_FREE(textDataLens); + return NITF_FAILURE; + } + endSize = nitf_IOInterface_getSize(writer->output, error); + if (!NITF_IO_SUCCESS(endSize)) + { + NITF_FREE(textSubLens); + NITF_FREE(textDataLens); + return NITF_FAILURE; + } + textSubLens[i] = endSize - startSize; + startSize = endSize; + /* TODO - we need to check to make sure the imageWriter exists */ + if (!writeText(writer->textWriters[i], + writer->output, error)) + { + NITF_FREE(textSubLens); + NITF_FREE(textDataLens); + return NITF_FAILURE; + } + endSize = nitf_IOInterface_getSize(writer->output, error); + if (!NITF_IO_SUCCESS(endSize)) + { + NITF_FREE(textSubLens); + NITF_FREE(textDataLens); + return NITF_FAILURE; + } + textDataLens[i] = endSize - startSize; + startSize = endSize; + + nitf_ListIterator_increment(&iter); + ++i; + } + } + + /*******************************************************************/ + /* START DEALING WITH DATA EXTENSIONS */ + /*******************************************************************/ + if (!nitf_Field_get(header->numDataExtensions, &numDEs, + NITF_CONV_INT, NITF_INT32_SZ, error)) + { + nitf_Error_init(error, "Could not retrieve number of data extensions", + NITF_CTXT, NITF_ERR_INVALID_OBJECT); + return NITF_FAILURE; + } + + /* TODO - WE NEED TO CHECK IF A WRITER IS SETUP FOR EACH SEGMENT */ + /* IF NOT, WE SHOULD NOT WRITE THE SEGMENT AT ALL, OR SET THE DATA TO 0 */ + + deSubLens = NULL; + deDataLens = NULL; + if (numDEs != 0) + { + + /* Length of current user subheader */ + nitf_Uint32 userSublen; + + deSubLens = (nitf_Off *) NITF_MALLOC(numDEs * sizeof(nitf_Off)); + if (!deSubLens) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + return NITF_FAILURE; + } + deDataLens = (nitf_Off *) NITF_MALLOC(numDEs * sizeof(nitf_Off)); + if (!deDataLens) + { + NITF_FREE(deSubLens); + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + return NITF_FAILURE; + } + + iter = nitf_List_begin(writer->record->dataExtensions); + end = nitf_List_end(writer->record->dataExtensions); + + startSize = nitf_IOInterface_getSize(writer->output, error); + if (!NITF_IO_SUCCESS(startSize)) + { + NITF_FREE(deSubLens); + NITF_FREE(deDataLens); + return NITF_FAILURE; + } + i = 0; /* reset the counter */ + while (nitf_ListIterator_notEqualTo(&iter, &end)) + { + nitf_DESegment *segment = + (nitf_DESegment *) nitf_ListIterator_get(&iter); + if (!writeDESubheader(writer, + segment->subheader, + &userSublen, fver, error)) + { + NITF_FREE(deSubLens); + NITF_FREE(deDataLens); + return NITF_FAILURE; + } + endSize = nitf_IOInterface_getSize(writer->output, error); + if (!NITF_IO_SUCCESS(endSize)) + { + NITF_FREE(deSubLens); + NITF_FREE(deDataLens); + return NITF_FAILURE; + } + deSubLens[i] = endSize - startSize; + startSize = endSize; + /* TODO - we need to check to make sure the imageWriter exists */ + if (!writeDE(writer, writer->dataExtensionWriters[i], + segment->subheader, writer->output, error)) + { + NITF_FREE(deSubLens); + NITF_FREE(deDataLens); + return NITF_FAILURE; + } + endSize = nitf_IOInterface_getSize(writer->output, error); + if (!NITF_IO_SUCCESS(endSize)) + { + NITF_FREE(deSubLens); + NITF_FREE(deDataLens); + return NITF_FAILURE; + } + deDataLens[i] = endSize - startSize; + startSize = endSize; + + nitf_ListIterator_increment(&iter); + ++i; + } + } + + /* Fix file and header lengths */ + + /* Get the file length */ + fileLen = nitf_IOInterface_getSize(writer->output, error); + + if (!NITF_IO_SUCCESS(fileLen)) + goto CATCH_ERROR; + + if (!NITF_IO_SUCCESS(nitf_IOInterface_seek(writer->output, + fileLenOff, + NITF_SEEK_SET, + error))) + goto CATCH_ERROR; + + NITF_WRITE_INT64_FIELD(fileLen, NITF_FL, ZERO, FILL_LEFT); + if (!nitf_Field_setUint64(header->NITF_FL, fileLen, error)) + goto CATCH_ERROR; + + NITF_WRITE_INT64_FIELD(hdrLen, NITF_HL, ZERO, FILL_LEFT); + if (!nitf_Field_setUint64(header->NITF_HL, hdrLen, error)) + goto CATCH_ERROR; + + + + /* Fix the image subheader and data lengths */ + NITF_WRITE_INT_FIELD(numImgs, NITF_NUMI, ZERO, FILL_LEFT); + if (!nitf_Field_setUint32(header->NITF_NUMI, numImgs, error)) + goto CATCH_ERROR; + for (i = 0; i < numImgs; i++) + { + NITF_WRITE_INT64_FIELD(imageSubLens[i], NITF_LISH, ZERO, FILL_LEFT); + if (!nitf_Field_setUint64(header->NITF_LISH(i), imageSubLens[i], error)) + goto CATCH_ERROR; + + NITF_WRITE_INT64_FIELD(imageDataLens[i], NITF_LI, ZERO, FILL_LEFT); + if (!nitf_Field_setUint64(header->NITF_LI(i), imageDataLens[i], error)) + goto CATCH_ERROR; + } + if (numImgs != 0) + { + NITF_FREE(imageSubLens); + NITF_FREE(imageDataLens); + } + + /* Fix the graphic subheader and data lengths */ + NITF_WRITE_INT_FIELD(numGraphics, NITF_NUMS, ZERO, FILL_LEFT); + if (!nitf_Field_setUint32(header->NITF_NUMS, numGraphics, error)) + goto CATCH_ERROR; + + for (i = 0; i < numGraphics; i++) + { + NITF_WRITE_INT64_FIELD(graphicSubLens[i], NITF_LSSH, ZERO, FILL_LEFT); + if (!nitf_Field_setUint64(header->NITF_LSSH(i), graphicSubLens[i], error)) + goto CATCH_ERROR; + + NITF_WRITE_INT64_FIELD(graphicDataLens[i], NITF_LS, ZERO, FILL_LEFT); + if (!nitf_Field_setUint64(header->NITF_LS(i), graphicDataLens[i], error)) + goto CATCH_ERROR; + + } + if (numGraphics != 0) + { + NITF_FREE(graphicSubLens); + NITF_FREE(graphicDataLens); + } + + /* NOW, we need to seek past the other count */ + skipBytes = NITF_NUMX_SZ; + if (!NITF_IO_SUCCESS(nitf_IOInterface_seek(writer->output, + skipBytes, + NITF_SEEK_CUR, + error))) + goto CATCH_ERROR; + + /* Fix the text subheader and data lengths */ + NITF_WRITE_INT_FIELD(numTexts, NITF_NUMT, ZERO, FILL_LEFT); + if (!nitf_Field_setUint32(header->NITF_NUMT, numTexts, error)) + goto CATCH_ERROR; + + for (i = 0; i < numTexts; i++) + { + NITF_WRITE_INT64_FIELD(textSubLens[i], NITF_LTSH, ZERO, FILL_LEFT); + if (!nitf_Field_setUint64(header->NITF_LTSH(i), textSubLens[i], error)) + goto CATCH_ERROR; + + + NITF_WRITE_INT64_FIELD(textDataLens[i], NITF_LT, ZERO, FILL_LEFT); + if (!nitf_Field_setUint64(header->NITF_LT(i), textSubLens[i], error)) + goto CATCH_ERROR; + + } + if (numTexts != 0) + { + NITF_FREE(textSubLens); + NITF_FREE(textDataLens); + } + + /* Fix the data extension subheader and data lengths */ + NITF_WRITE_INT_FIELD(numDEs, NITF_NUMDES, ZERO, FILL_LEFT); + if (!nitf_Field_setUint32(header->NITF_NUMDES, numDEs, error)) + goto CATCH_ERROR; + + for (i = 0; i < numDEs; i++) + { + NITF_WRITE_INT64_FIELD(deSubLens[i], NITF_LDSH, ZERO, FILL_LEFT); + if (!nitf_Field_setUint64(header->NITF_LDSH(i), deSubLens[i], error)) + goto CATCH_ERROR; + + + NITF_WRITE_INT64_FIELD(deDataLens[i], NITF_LD, ZERO, FILL_LEFT); + if (!nitf_Field_setUint64(header->NITF_LD(i), deDataLens[i], error)) + goto CATCH_ERROR; + + + } + if (numDEs != 0) + { + NITF_FREE(deSubLens); + NITF_FREE(deDataLens); + } + + /* Now its time to check if we should be measuring the CLEVEL */ + if (strncmp(header->NITF_CLEVEL->raw, "00", 2) == 0) + { + NITF_CLEVEL clevel = + nitf_ComplexityLevel_measure(writer->record, error); + + if (clevel == NITF_CLEVEL_CHECK_FAILED) + goto CATCH_ERROR; + + nitf_ComplexityLevel_toString(clevel, + header->NITF_CLEVEL->raw); + + if (!NITF_IO_SUCCESS(nitf_IOInterface_seek(writer->output, + NITF_FHDR_SZ + NITF_FVER_SZ, + NITF_SEEK_SET, + error))) + goto CATCH_ERROR; + + + if (!writeField(writer, header->NITF_CLEVEL->raw, 2, error)) + goto CATCH_ERROR; + } + + /* if there wasn't a file datetime set, let's set one automatically */ + if (nitf_Utils_isBlank(header->NITF_FDT->raw)) + { + char *dateFormat = (nitf_Record_getVersion(writer->record) == NITF_VER_20 ? + NITF_DATE_FORMAT_20 : NITF_DATE_FORMAT_21); + + if (!nitf_Field_setDateTime(header->NITF_FDT, NULL, dateFormat, error)) + goto CATCH_ERROR; + + if (!NITF_IO_SUCCESS(nitf_IOInterface_seek(writer->output, + NITF_FHDR_SZ + NITF_FVER_SZ + NITF_CLEVEL_SZ + NITF_STYPE_SZ + NITF_OSTAID_SZ, + NITF_SEEK_SET, error))) + goto CATCH_ERROR; + + if (!writeField(writer, header->NITF_FDT->raw, NITF_FDT_SZ, error)) + goto CATCH_ERROR; + } + + nitf_Writer_destructWriters(writer); + + /* We dont handle anything cool yet */ + return NITF_SUCCESS; + +CATCH_ERROR: + + nitf_Writer_destructWriters(writer); + + if (numImgs != 0) + { + NITF_FREE(imageSubLens); + NITF_FREE(imageDataLens); + } + if (numGraphics != 0) + { + NITF_FREE(graphicSubLens); + NITF_FREE(graphicDataLens); + } + if (numTexts != 0) + { + NITF_FREE(textSubLens); + NITF_FREE(textDataLens); + } + if (numDEs != 0) + { + NITF_FREE(deSubLens); + NITF_FREE(deDataLens); + } + + return NITF_FAILURE; +} + + +NITFAPI(NITF_BOOL) nitf_Writer_setImageWriteHandler(nitf_Writer *writer, + int index, nitf_WriteHandler *writeHandler, nitf_Error * error) +{ + if (index >= writer->numImageWriters) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_INVALID_PARAMETER, + "index is greater than number of images"); + goto CATCH_ERROR; + } + /* destroy any previously existing one */ + if (writer->imageWriters[index]) + nitf_WriteHandler_destruct(&writer->imageWriters[index]); + writer->imageWriters[index] = writeHandler; + return NITF_SUCCESS; + +CATCH_ERROR: + return NITF_FAILURE; +} + +NITFAPI(NITF_BOOL) nitf_Writer_setGraphicWriteHandler(nitf_Writer *writer, + int index, nitf_WriteHandler *writeHandler, nitf_Error * error) +{ + if (index >= writer->numGraphicWriters) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_INVALID_PARAMETER, + "index is greater than number of graphics"); + goto CATCH_ERROR; + } + /* destroy any previously existing one */ + if (writer->graphicWriters[index]) + nitf_WriteHandler_destruct(&writer->graphicWriters[index]); + writer->graphicWriters[index] = writeHandler; + return NITF_SUCCESS; + +CATCH_ERROR: + return NITF_FAILURE; +} + +NITFAPI(NITF_BOOL) nitf_Writer_setTextWriteHandler(nitf_Writer *writer, + int index, nitf_WriteHandler *writeHandler, nitf_Error * error) +{ + if (index >= writer->numTextWriters) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_INVALID_PARAMETER, + "index is greater than number of texts"); + goto CATCH_ERROR; + } + /* destroy any previously existing one */ + if (writer->textWriters[index]) + nitf_WriteHandler_destruct(&writer->textWriters[index]); + writer->textWriters[index] = writeHandler; + return NITF_SUCCESS; + +CATCH_ERROR: + return NITF_FAILURE; +} + +NITFAPI(NITF_BOOL) nitf_Writer_setDEWriteHandler(nitf_Writer *writer, + int index, nitf_WriteHandler *writeHandler, nitf_Error * error) +{ + if (index >= writer->numDataExtensionWriters) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_INVALID_PARAMETER, + "index is greater than number of images"); + goto CATCH_ERROR; + } + /* destroy any previously existing one */ + if (writer->dataExtensionWriters[index]) + nitf_WriteHandler_destruct(&writer->dataExtensionWriters[index]); + writer->dataExtensionWriters[index] = writeHandler; + return NITF_SUCCESS; + +CATCH_ERROR: + return NITF_FAILURE; +} + + +NITFAPI(nitf_ImageWriter *) +nitf_Writer_newImageWriter(nitf_Writer *writer, + int index, + nrt_HashTable* options, + nitf_Error * error) +{ + nitf_ListIterator iter; + nitf_ImageWriter *imageWriter = NULL; + nitf_ImageSegment *currentSegment = NULL; + + /* currently always NULL */ + /*nitf_CompressionInterface *compIface = NULL;*/ + + if (index >= writer->numImageWriters) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_INVALID_PARAMETER, + "index is greater than number of images"); + goto CATCH_ERROR; + } + + iter = nitf_List_at(writer->record->images, index); + /* this operation will assert if it is the end of the list */ + currentSegment = (nitf_ImageSegment *) nitf_ListIterator_get(&iter); + + assert(currentSegment); + assert(currentSegment->subheader); + + imageWriter = nitf_ImageWriter_construct(currentSegment->subheader, + options, error); + if (!imageWriter) + goto CATCH_ERROR; + + if (!nitf_Writer_setImageWriteHandler(writer, index, imageWriter, error)) + goto CATCH_ERROR; + + return imageWriter; + +CATCH_ERROR: + if (imageWriter) + nitf_WriteHandler_destruct(&imageWriter); + return NULL; +} + + +NITFAPI(nitf_SegmentWriter *) nitf_Writer_newTextWriter +( + nitf_Writer * writer, + int index, + nitf_Error * error +) +{ + nitf_SegmentWriter *segmentWriter = NULL; + + if (index >= writer->numTextWriters) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_INVALID_PARAMETER, + "i is greater than number of texts"); + return NULL; + } + + segmentWriter = nitf_SegmentWriter_construct(error); + if (!segmentWriter) + return NULL; + + if (!nitf_Writer_setTextWriteHandler(writer, index, segmentWriter, error)) + return NULL; + + return segmentWriter; +} + +NITFAPI(nitf_SegmentWriter *) nitf_Writer_newDEWriter +( + nitf_Writer * writer, + int index, + nitf_Error * error +) +{ + nitf_SegmentWriter *segmentWriter = NULL; + + if (index >= writer->numDataExtensionWriters) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_INVALID_PARAMETER, + "i is greater than number of DE segments"); + return NULL; + } + + segmentWriter = nitf_SegmentWriter_construct(error); + if (!segmentWriter) + return NULL; + + if (!nitf_Writer_setDEWriteHandler(writer, index, segmentWriter, error)) + return NULL; + + return segmentWriter; +} + + +NITFAPI(nitf_SegmentWriter *) nitf_Writer_newGraphicWriter +( + nitf_Writer * writer, + int index, + nitf_Error * error +) +{ + nitf_SegmentWriter *segmentWriter = NULL; + + if (index >= writer->numGraphicWriters) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_INVALID_PARAMETER, + "i is greater than number of graphics"); + return NULL; + } + + segmentWriter = nitf_SegmentWriter_construct(error); + if (!segmentWriter) + return NULL; + + if (!nitf_Writer_setGraphicWriteHandler(writer, index, segmentWriter, error)) + return NULL; + + return segmentWriter; +} + diff --git a/modules/c/nitf/source/wscript_build b/modules/c/nitf/source/wscript_build new file mode 100644 index 000000000..da72eca80 --- /dev/null +++ b/modules/c/nitf/source/wscript_build @@ -0,0 +1,33 @@ +# encoding: utf-8 + +import os, glob, re +import Params + +ENV = bld.m_allenvs['default'] +APPNAME = ENV['APPNAME'] +VERSION = ENV['VERSION'] +LIB_NAME = APPNAME +INCLUDES = ['../include/'] +SOURCES = [os.path.split(p)[1] for p in glob.glob(os.path.join(bld.m_curdirnode.abspath(), '*.c'))] + +if 'SOURCE_FILTER' in ENV: + sourceFilter = re.compile(ENV['SOURCE_FILTER'], re.I) + filtered = [] + for s in SOURCES: + if sourceFilter.match(s) == None: + filtered.append(s) + SOURCES = filtered + +# objects +obj = bld.create_obj('cc', 'objects') +obj.source = SOURCES +obj.includes = INCLUDES +obj.target = "%s-objects" % APPNAME + +# static library +obj = bld.create_obj('cc', 'staticlib') +obj.name = '%s-static' % APPNAME +obj.target = '%s-c' % LIB_NAME +obj.env = ENV +obj.add_objects = "%s-objects" % APPNAME +obj.uselib = APPNAME diff --git a/modules/c/nitf/tests/test_1band_rw_line.c b/modules/c/nitf/tests/test_1band_rw_line.c new file mode 100644 index 000000000..b9e1b72f8 --- /dev/null +++ b/modules/c/nitf/tests/test_1band_rw_line.c @@ -0,0 +1,308 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + +void writeImage(nitf_ImageSegment* segment, + nitf_IOHandle io, + char* imageName, + nitf_Record* record, + int imageNumber, + nitf_Error* error) +{ + + nitf_Uint32 nBits, nBands, xBands, nRows, nColumns; + size_t subimageSize; + nitf_SubWindow *subimage; + unsigned int i; + + int padded; + nitf_Uint8** buffer; + nitf_Uint32 band; + nitf_Uint32 *bandList; + char file[NITF_MAX_PATH]; + + nitf_IOHandle toFile; + + NITF_TRY_GET_UINT32(segment->subheader->numBitsPerPixel, &nBits, error ); + NITF_TRY_GET_UINT32(segment->subheader->numImageBands, &nBands, error ); + NITF_TRY_GET_UINT32(segment->subheader->numMultispectralImageBands, &xBands, error ); + nBands += xBands; + NITF_TRY_GET_UINT32(segment->subheader->numRows, &nRows, error ); + NITF_TRY_GET_UINT32(segment->subheader->numCols, &nColumns, error ); + + printf("Image number: %d\n", imageNumber); + printf("\nCLEVEL -> %.*s\n" + "NBANDS -> %d\n" + "XBANDS -> %d\n" + "NROWS -> %d\n" + "NCOLS -> %d\n" + "PVTYPE -> %.*s\n" + "NBPP -> %.*s\n" + "ABPP -> %.*s\n" + "PJUST -> %.*s\n" + "IMODE -> %.*s\n" + "NBPR -> %.*s\n" + "NBPC -> %.*s\n" + "NPPBH -> %.*s\n" + "NPPBV -> %.*s\n" + "IC -> %.*s\n" + "COMRAT -> %.*s\n", + record->header->complianceLevel->length, + record->header->complianceLevel->raw, + nBands, + xBands, + nRows, + nColumns, + segment->subheader->pixelValueType->length, + segment->subheader->pixelValueType->raw, + segment->subheader->numBitsPerPixel->length, + segment->subheader->numBitsPerPixel->raw, + segment->subheader->actualBitsPerPixel->length, + segment->subheader->actualBitsPerPixel->raw, + segment->subheader->pixelJustification->length, + segment->subheader->pixelJustification->raw, + segment->subheader->imageMode->length, + segment->subheader->imageMode->raw, + segment->subheader->numBlocksPerRow->length, + segment->subheader->numBlocksPerRow->raw, + segment->subheader->numBlocksPerCol->length, + segment->subheader->numBlocksPerCol->raw, + segment->subheader->numPixelsPerHorizBlock->length, + segment->subheader->numPixelsPerHorizBlock->raw, + segment->subheader->numPixelsPerVertBlock->length, + segment->subheader->numPixelsPerVertBlock->raw, + segment->subheader->imageCompression->length, + segment->subheader->imageCompression->raw, + segment->subheader->compressionRate->length, + segment->subheader->compressionRate->raw); + + if (nBands != 1) + { + printf("This is a single band test case, but the image is multi-band. Exiting...\n"); + exit(EXIT_FAILURE); + } + buffer = (nitf_Uint8 **)malloc(sizeof(nitf_Uint8)); // Malloc one dimension + band = 0; + bandList = (nitf_Uint32 *)malloc(sizeof(nitf_Uint32)); + + subimage = nitf_SubWindow_construct(&error); + assert(subimage); + + subimage->startCol = 0; + subimage->startRow = 0; + subimage->numRows = 1;/*nRows;*/ + subimage->numCols = nColumns; + /*subimageSize = nRows * nColumns * NITF_NBPP_TO_BYTES(nBits);*/ + subimageSize = nColumns * NITF_NBPP_TO_BYTES(nBits); + printf("Subimage size = %d, nBytes = %d\n", + subimageSize, + NITF_NBPP_TO_BYTES(nBits)); + for (band = 0; band < nBands; band++) + bandList[band] = band; + subimage->bandList = bandList; + subimage->numBands = nBands; + + assert(buffer); + buffer[0] = (nitf_Uint8*)malloc(subimageSize); + + + /* find end slash */ + for (i = strlen(imageName) - 1; + i && imageName[i] != '\\' && imageName[i] != '/'; + i--); + + NITF_SNPRINTF(file, NITF_MAX_PATH, "%s_%d__%d_%d_%d_per_line_1band", + &imageName[i + 1], imageNumber, nRows, nColumns, nBits); + + + for (i = strlen(file) - 1; i; i--) + { + if (file[i] == '.') + { + file[i] = '_'; + } + } + strcat(file, ".out"); + + printf("Filename: %s\n", file); + + toFile = nitf_IOHandle_create(file, NITF_ACCESS_WRITEONLY, + NITF_CREATE | NITF_TRUNCATE, + error); + if (! NITF_IO_SUCCESS(toFile)) + { + nitf_Error_print(error, stderr, "nitf::IOHandle::create() failed"); + goto CATCH_ERROR; + + } + + + for (i = 0; i < nRows; i++) + { + subimage->startRow = i; + /* This should change to returning failures! */ + printf("Reading one line... "); + if (!nitf_ImageIO_read(segment->imageIO, + io, + subimage, + buffer, + &padded, + error) ) + { + printf("failed!\n"); + nitf_Error_print(error, stderr, "Read failed"); + + goto CATCH_ERROR; + } + + printf("done\n"); + + printf("Writing one line... "); + if (!nitf_IOHandle_write(toFile, + (const char*)buffer[0], + subimageSize, error)) + + { + printf("failed!\n"); + nitf_Error_print(error, + stderr, + "write failed"); + break; + } + printf("done\n"); + + } + + + + nitf_IOHandle_close(toFile); + + free(buffer[0]); + free(buffer); + free(bandList); + + return; + +CATCH_ERROR: + free(buffer[0]); + free(buffer); + free(bandList); + printf("ERROR processing\n"); + +} +int main(int argc, char **argv) +{ + + /* This is the error we hopefully wont receive */ + nitf_Error e; + + /* This is the reader */ + nitf_Reader* reader; + + /* This is the record of the file we are reading */ + nitf_Record* record; + + + /* This is the io handle we will give the reader to parse */ + nitf_IOHandle io; + + int count = 0; + + + /* These iterators are for going through the image segments */ + nitf_ListIterator iter; + nitf_ListIterator end; + + /* If you didnt give us a nitf file, we're croaking */ + if (argc != 2) + { + printf("Usage: %s \n", argv[0]); + exit(EXIT_FAILURE); + } + + + reader = nitf_Reader_construct(&e); + if (!reader) + { + nitf_Error_print(&e, stderr, "nitf::Reader::construct() failed"); + exit(EXIT_FAILURE); + } + + record = nitf_Record_construct(&e); + if (!record) + { + nitf_Error_print(&e, stderr, "nitf::Record::construct() failed"); + exit(EXIT_FAILURE); + } + + /* If you did, though, we'll be nice and open it for you */ + io = nitf_IOHandle_create(argv[1], NITF_ACCESS_READONLY, + NITF_OPEN_EXISTING, &e); + + /* But, oh boy, if you gave us a bad location...! */ + if ( NITF_INVALID_HANDLE( io ) ) + { + /* You had this coming! */ + nitf_Error_print(&e, stderr, "nitf::IOHandle::create() failed"); + exit(EXIT_FAILURE); + } + + /* Read the file */ + if (! nitf_Reader_read(reader, + io, + record, + &e) ) + { + nitf_Error_print(&e, stderr, "nitf::Reader::read() failed"); + exit(EXIT_FAILURE); + } + + /* Set the iterator to traverse the list of image segments */ + iter = nitf_List_begin(record->images); + /* And set this one to the end, so we'll know when we're done! */ + end = nitf_List_end(record->images); + + /* While we are not done... */ + while ( nitf_ListIterator_notEqualTo(&iter, &end) ) + { + + /* Get the image segment as its proper object */ + nitf_ImageSegment* imageSegment = + (nitf_ImageSegment*)nitf_ListIterator_get(&iter); + + printf("Writing image %d... ", count); + + /* Write the thing out */ + writeImage(imageSegment, io, argv[1], record, count, &e); + printf("done.\n"); + /* Increment the iterator so we can continue */ + nitf_ListIterator_increment(&iter); + count++; + } + + nitf_Record_destruct(&record); + nitf_Reader_destruct(&reader); + nitf_IOHandle_close(io); + + return 0; +} diff --git a/modules/c/nitf/tests/test_ImageIO.h b/modules/c/nitf/tests/test_ImageIO.h new file mode 100644 index 000000000..5ebbfac8f --- /dev/null +++ b/modules/c/nitf/tests/test_ImageIO.h @@ -0,0 +1,289 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +/*! + + \file + \brief Include file for support functions for the NITF ImageIO library tests + + This include file defines support functions and structures used by + stand-alone test programs for the NITF ImageIO libary. Stand-alone means + programs that do not require any NITF header interpretation functionality. + +*/ + +#ifndef TEST_NITF_IMAGE_IO_INCLUDED +#define TEST_NITF_IMAGE_IO_INCLUDED + +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + + /*! \def TEST_NITF_IMAGE_IO_MAX_STRING - Longest string in test setup + structures */ +#define TEST_NITF_IMAGE_IO_MAX_STRING 256 + + /*! \def TEST_NITF_IMAGE_IO_MAX_BANDS - Upper limit on band count */ +#define TEST_NITF_IMAGE_IO_MAX_BANDS 32 + + /*! + + \brief test_nitf_ImageIOConstructArgs - Structure that holds arguments for + nitf_ImageIOConstruct + + This structure is used to facilitate reading files that contain argument + values (e,g., a test vector). The error buffer argument is not included + + The pad value array has storage for the largest posisble pad value (8). The + value is stored in native order. + */ + + typedef struct + { + nitf_Uint32 nRows; /*!< Number of rows in the image */ + nitf_Uint32 nColumns; /*!< Number of columns in the image */ + nitf_Uint32 nBands; /*!< Number of bands */ + nitf_Uint32 nMultiBands; /*!< Number of mutli-spectral bands */ + char pixelType[TEST_NITF_IMAGE_IO_MAX_STRING+2]; /*!< Pixel type */ + nitf_Uint32 nBits; /*!< Number of bits per pixel */ + nitf_Uint32 nBitsActual; /*!< Actual number of bits per pixel */ + char justify[TEST_NITF_IMAGE_IO_MAX_STRING+2]; /*!< ;Pixels justification */ + nitf_Uint32 nBlksPerRow; /*!< Number of blocks per row */ + nitf_Uint32 nBlksPerColumn; /*!< Number of blocks per Columns */ + nitf_Uint32 nRowsPerBlk; /*!< Number of rows per block */ + nitf_Uint32 nColumnsPerBlk; /*!< Number of columns per block */ + char mode[TEST_NITF_IMAGE_IO_MAX_STRING+2]; /*!< Blocking mode */ + char compression[TEST_NITF_IMAGE_IO_MAX_STRING+2]; /*!< Compression type */ + nitf_Uint8 padValue[8]; /*!< Pad value */ + nitf_Uint32 offset; /*!< Byte offset in file to image data segment */ + char dataPattern[TEST_NITF_IMAGE_IO_MAX_STRING+2]; /*!< Pattern gen method */ + } + test_nitf_ImageIOConstructArgs; + + /*! + + \brief test_nitf_ImageIOReadArgs - Structure that holds arguments for + nitf_ImageIORead + + The nitf", "fd", "user", and "padded" arguments are not represented in the + structure. + + */ + + typedef struct + { + char name[TEST_NITF_IMAGE_IO_MAX_STRING+2]; /*!< File name to read */ + nitf_Uint32 row; /*!< Start row */ + nitf_Uint32 nRows; /*!< Number of rows to read */ + nitf_Uint32 rowSkip; /*!< Row skip factor */ + nitf_Uint32 column; /*!< Start column */ + nitf_Uint32 nColumns; /*!< Number of columns to read */ + nitf_Uint32 columnSkip; /*!< Column skip factor */ + char + downSample[TEST_NITF_IMAGE_IO_MAX_STRING+2];/*!< Down-sample method */ + nitf_Uint32 nBands; /*!< Number of bands to read */ + nitf_Uint32 bands[TEST_NITF_IMAGE_IO_MAX_BANDS]; /*!< Bands to read */ + } + test_nitf_ImageIOReadArgs; + + /*! + \brief test_nitf_ImageIOReadConstructArgs - Read argument file for + nitf_ImageIOConstruct call + + Read values from the file stream and initialize a argument structure. + One value is read from each line. The lines in the file should give the + values in the order they appear in the test_nitf_ImageIOConstructArgs + structure. Each line can contain a comment following the value. The comment + should be separated from the value by white space. + + On error, the error string argument is set. Error messages are not + terminated by \\n + + \return The initialized structure or NULL on error + + */ + + NITFAPI(test_nitf_ImageIOConstructArgs *) test_nitf_ImageIOReadConstructArgs + ( + FILE *file, /*!< The file to read */ + char **error /*!< Returns an error message on error */ + ); + + /*! + \brief test_nitf_ImageIOReadReadArgs - Read argument file for + nitf_ImageIORead call + + Read values from the file stream and initialize a argument structure. + One value is read from each line. The lines in the file should give the + values in the order they appear in the test_nitf_ImageIOReadArgs structure. + Each line can contain a comment following the value. The comment should be + separated from the value by white space. The band numbers in the "bands" + array should be one per line + + On error, the error string argument is set. Error messages are not + terminated by \\n + + \return Returns an intialized test_nitf_ImageIOReadArgs structure or NULL + + */ + + NITFAPI(test_nitf_ImageIOReadArgs *) test_nitf_ImageIOReadReadArgs + ( + FILE *file, /*!< The file to read */ + char **error /*!< Returns an error message on error */ + ); + + + /*! + \brief test_nitf_ImageIO_mkArray - Create image array + + test_nitf_ImageIO_mkArray creates an image array with dimensions + [bands][rows][columns]. The dimensions are taken from the construct + arguments structure as is the pixel size in bytes + + test_nitf_ImageIO_freeArray should be used to free this array + + /return Returns the array. On error, NULL is returned and the error + string is set + */ + + NITFAPI(void *) test_nitf_ImageIO_mkArray + ( + test_nitf_ImageIOConstructArgs *args, /*!< Supplies dimensions and size */ + char **error /*!< Returns an error message on error */ + ); + + /*! + \brief test_nitf_ImageIO_freeArray - Free image array + + \return None + */ + + NITFAPI(void) test_nitf_ImageIO_freeArray + ( + nitf_Uint8 ***data /*!< The array to free */ + ); + + /*! + \brief test_nitf_ImageIO_brcI4 - Create a band/row/colum I4 image array + + test_nitf_ImageIO_brcI4 creates a three dimensional image array of 32 bit + integers where: + + data[band][row][col] = (band << 16) + (row << 8) + col + + /return Returns the array. On error, NULL is returned and the error + string is set + */ + + NITFAPI(void *) test_nitf_ImageIO_brcI4 + ( + test_nitf_ImageIOConstructArgs *args, /*!< Supplies dimensions and size */ + char **error /*!< Returns an error message on error */ + ); + + /*! + \brief test_nitf_ImageIO_brcC8 - Create a band/row/colum C8 image array + + test_nitf_ImageIO_brcI4 creates a thredimensional image array of single + precision complex (float real followed by float imaginary) where: + + data[band][row][col].r = band*100 + row + data[band][row][col].i = band*100 + col + + /return Returns the array. On error, NULL is returned and the error + string is set + */ + + NITFAPI(void *) test_nitf_ImageIO_brcC8 + ( + test_nitf_ImageIOConstructArgs *args, /*!< Supplies dimensions and size */ + char **error /*!< Returns an error message on error */ + ); + + /*! + \brief test_nitf_ImageIO_Block - Create a block pattern + + test_nitf_ImageIO_block creates a three dimensional image array of + one byte data. The data is: + + data[band][row][col] = band+1; + + Block pattern generator. The data is generated based on the blocking + structure and a mask. The mask specifies which blocks are present and + which are missing. For missing blocks the data is 0 for present blocks + the data is the band number + + The mask is determined by the data generator tag. The tag always starts + with "block_". The rest of the tag is the specification + + The specification is a single string composed of the row strings of the + desired result. Each row sub-string is separated by an _. Each row string + contains a character for each block in the row. If the character is "M" + the block is missing, if it is "P" the block is present + + /return Returns the array. On error, NULL is returned and the error + string is set + */ + + NITFAPI(void *) test_nitf_ImageIO_block + ( + test_nitf_ImageIOConstructArgs *args, /*!< Supplies dimensions and size */ + char **error /*!< Returns an error message on error */ + ); + + /*! + \brief test_nitf_ImageIO_bigEndian - Test for Big endian system + + \return TRUE when called on a big-endian system + */ + + NITFAPI(int) test_nitf_ImageIO_bigEndian(void); + + /*========================= test_nitf_ImageIO_fakeSubheader ==================*/ + + /*! + \brief test_nitf_fakeSubheader - Create partially initialized image + subheader object. + + \b test_nitf_fakeSubheader creates partially initialized image subheader + object. This object can be used to construct a nitf_ImageIO object + + /return Returns the object. On error, NULL is returned and the error + string is set. + */ + + NITFAPI(nitf_ImageSubheader *) test_nitf_ImageIO_fakeSubheader + ( + test_nitf_ImageIOConstructArgs *args, /*!< Supplies dimensions and size */ + char **error /*!< Returns an error message on error */ + ); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/modules/c/nitf/tests/test_ImageIO_read_data.c b/modules/c/nitf/tests/test_ImageIO_read_data.c new file mode 100644 index 000000000..bbbb59336 --- /dev/null +++ b/modules/c/nitf/tests/test_ImageIO_read_data.c @@ -0,0 +1,353 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +/* +* Test program for nitf_ImageIO_read +* +* This program reads an image based on two "vectors" (text files). The first +* defines the layout of the image data section (the binary part of the image +* segment including the masks). The second defines the read operation +* including the filename and sub-window specification +* +* The read data is written as flat binary files, one per requested band +* +* The first argument is the image vector and the second is the read +* vector. The remaining arguments are the outputs, one per requested band +* +*/ + +#include +#include +#include +#include +#include + +#include "test_ImageIO.h" + +NITFAPI(void) nitf_ImageIO_print( + nitf_ImageIO *nitf,/* nitf_ImageIO object */ + FILE *file /* FILE to use for print */ +); + +int main(int argc, char *argv[]) +{ + nitf_ImageIO *nitf; /* The parent nitf_ImageIO object */ + char errorBuf[NITF_MAX_EMESSAGE]; /* Error buffer */ + nitf_Uint8 **user; /* User buffer list */ + int padded; /* Pad pixel present flag */ + nitf_IOHandle fileHandle; /* I/O handle for reads */ + int ofd; /* File descriptor for writes */ + FILE *vector; /* FILE for reading vectors */ + test_nitf_ImageIOConstructArgs *newArgs;/* Arguments for new */ + test_nitf_ImageIOReadArgs *readArgs; /* Arguments for read */ + nitf_ImageSubheader *subheader; /* For constructor */ + size_t subWindowSize; /* Sub-window pixel count */ + nitf_SubWindow *subWindow; /* Argument for read */ + nitf_DownSampler* downSampler; /* Down-sample object */ + char *error; /* Error message return */ + nitf_Error errorObjActual; /* Error object instance */ + nitf_Error *errorObj; /* Error object (pointer) */ + int i; + + errorObj = &errorObjActual; + + /* Usage */ + + if (argc < 2) + { + fprintf(stderr, + "Usage: %s imageVector readVector band0Out band1Out ... >result\n", argv[0]); + exit(0); + } + + /* Read image and read parameters from first and second arguments */ + + vector = fopen(argv[1], "r"); + if (vector == NULL) + { + fprintf(stderr, "Error opening image vector file %s\n", argv[0]); + exit(-1); + } + + newArgs = test_nitf_ImageIOReadConstructArgs(vector, &error); + if (newArgs == NULL) + { + fprintf(stderr, "%s\n", error); + exit(-1); + } + fclose(vector); + + vector = fopen(argv[2], "r"); + if (vector == NULL) + { + fprintf(stderr, "Error opening read vector file %s\n", argv[0]); + exit(-1); + } + + readArgs = test_nitf_ImageIOReadReadArgs(vector, &error); + if (readArgs == NULL) + { + fprintf(stderr, "%s\n", error); + exit(-1); + } + fclose(vector); + + /* Allocate user buffers */ + + subWindowSize = (readArgs->nRows) * (readArgs->nColumns) * (newArgs->nBits / 8); + + user = (nitf_Uint8 **) malloc(sizeof(nitf_Uint8 *) * (readArgs->nBands)); + if (user == NULL) + { + fprintf(stderr, "Error allocating user buffer\n"); + exit(-1); + } + + for (i = 0;i < readArgs->nBands;i++) + { + user[i] = (nitf_Uint8 *) malloc(subWindowSize); + if (user[i] == NULL) + { + fprintf(stderr, "Error allocating user buffer\n"); + exit(-1); + } + } + + /* Create a fake image subheader to give to ImageIO constructor */ + + subheader = test_nitf_ImageIO_fakeSubheader(newArgs, &error); + if (subheader == NULL) + { + fprintf(stderr, "%s", error); + exit(-1); + } + + /* Create the ImageIO */ + + nitf = nitf_ImageIO_construct(subheader, newArgs->offset, + 0,/*length, must be correct for decompression */ + NULL, NULL, errorObj); + if (nitf == NULL) + { + fprintf(stderr, "NtfBlk new failed: %s\n", errorBuf); + fprintf(stderr, "Err: %s\n", errorObj->message); + exit(0); + } + + nitf_ImageIO_setPadPixel(nitf, newArgs->padValue, + NITF_NBPP_TO_BYTES(newArgs->nBits)); + + nitf_ImageIO_print(nitf, stdout); + + /* Open input file */ + + fileHandle = nitf_IOHandle_create(readArgs->name, + NITF_ACCESS_READONLY, 0, errorObj); + if (NITF_INVALID_HANDLE(fileHandle)) + { + nitf_Error_init(errorObj, "File open failed", + NITF_CTXT, NITF_ERR_OPENING_FILE); + nitf_Error_print(errorObj, stderr, "File open failed"); + exit(0); + } + + /* Setup for read (create and initialize sub-window object */ + + if ((subWindow = nitf_SubWindow_construct(errorObj)) == NULL) + { + nitf_Error_init(errorObj, "Sub-window object construct failed", + NITF_CTXT, NITF_ERR_INVALID_OBJECT); + nitf_Error_print(errorObj, stderr, "Sub-window object construct failed"); + nitf_IOHandle_close(fileHandle); + nitf_ImageIO_destruct(&nitf); + exit(0); + } + + subWindow->startRow = readArgs->row; + subWindow->numRows = readArgs->nRows; + subWindow->startCol = readArgs->column; + subWindow->numCols = readArgs->nColumns; + subWindow->bandList = readArgs->bands; + subWindow->numBands = readArgs->nBands; + + if ((readArgs->rowSkip != 1) || (readArgs->columnSkip != 1)) + { + if (strcmp(readArgs->downSample, "pixelSkip") == 0) + { + if ((downSampler = nitf_PixelSkip_construct( + readArgs->rowSkip, readArgs->columnSkip, errorObj)) == NULL) + { + nitf_Error_init(errorObj, "Down-sampler object construct failed", + NITF_CTXT, NITF_ERR_INVALID_OBJECT); + nitf_Error_print(errorObj, stderr, + "Down-sampler object construct failed"); + nitf_IOHandle_close(fileHandle); + nitf_ImageIO_destruct(&nitf); + nitf_SubWindow_destruct(&subWindow); + exit(0); + } + + if (nitf_SubWindow_setDownSampler( + subWindow, downSampler, errorObj) == NITF_FAILURE) + { + nitf_Error_init(errorObj, "Read failed", + NITF_CTXT, NITF_ERR_READING_FROM_FILE); + nitf_Error_print(errorObj, stderr, "Read failed"); + nitf_IOHandle_close(fileHandle); + nitf_ImageIO_destruct(&nitf); + nitf_SubWindow_destruct(&subWindow); + nitf_DownSampler_destruct(&downSampler); + exit(0); + } + } + else if (strcmp(readArgs->downSample, "max") == 0) + { + + if ((downSampler = nitf_MaxDownSample_construct( + readArgs->rowSkip, readArgs->columnSkip, errorObj)) == NULL) + { + nitf_Error_init(errorObj, "Down-sampler object construct failed", + NITF_CTXT, NITF_ERR_INVALID_OBJECT); + nitf_Error_print(errorObj, stderr, + "Down-sampler object construct failed"); + nitf_IOHandle_close(fileHandle); + nitf_ImageIO_destruct(&nitf); + nitf_SubWindow_destruct(&subWindow); + exit(0); + } + + if (nitf_SubWindow_setDownSampler( + subWindow, downSampler, errorObj) == NITF_FAILURE) + { + nitf_Error_init(errorObj, "Read failed", + NITF_CTXT, NITF_ERR_READING_FROM_FILE); + nitf_Error_print(errorObj, stderr, "Read failed"); + nitf_IOHandle_close(fileHandle); + nitf_ImageIO_destruct(&nitf); + nitf_SubWindow_destruct(&subWindow); + nitf_DownSampler_destruct(&downSampler); + exit(0); + } + } + else if (strcmp(readArgs->downSample, "sumSq2") == 0) + { + + if ((downSampler = nitf_SumSq2DownSample_construct( + readArgs->rowSkip, readArgs->columnSkip, errorObj)) == NULL) + { + nitf_Error_init(errorObj, "Down-sampler object construct failed", + NITF_CTXT, NITF_ERR_INVALID_OBJECT); + nitf_Error_print(errorObj, stderr, + "Down-sampler object construct failed"); + nitf_IOHandle_close(fileHandle); + nitf_ImageIO_destruct(&nitf); + nitf_SubWindow_destruct(&subWindow); + exit(0); + } + + if (nitf_SubWindow_setDownSampler( + subWindow, downSampler, errorObj) == NITF_FAILURE) + { + nitf_Error_init(errorObj, "Read failed", + NITF_CTXT, NITF_ERR_READING_FROM_FILE); + nitf_Error_print(errorObj, stderr, "Read failed"); + nitf_IOHandle_close(fileHandle); + nitf_ImageIO_destruct(&nitf); + nitf_SubWindow_destruct(&subWindow); + nitf_DownSampler_destruct(&downSampler); + exit(0); + } + } + else if (strcmp(readArgs->downSample, "select2") == 0) + { + + if ((downSampler = nitf_Select2DownSample_construct( + readArgs->rowSkip, readArgs->columnSkip, errorObj)) == NULL) + { + nitf_Error_init(errorObj, "Down-sampler object construct failed", + NITF_CTXT, NITF_ERR_INVALID_OBJECT); + nitf_Error_print(errorObj, stderr, + "Down-sampler object construct failed"); + nitf_IOHandle_close(fileHandle); + nitf_ImageIO_destruct(&nitf); + nitf_SubWindow_destruct(&subWindow); + exit(0); + } + + if (nitf_SubWindow_setDownSampler( + subWindow, downSampler, errorObj) == NITF_FAILURE) + { + nitf_Error_init(errorObj, "Read failed", + NITF_CTXT, NITF_ERR_READING_FROM_FILE); + nitf_Error_print(errorObj, stderr, "Read failed"); + nitf_IOHandle_close(fileHandle); + nitf_ImageIO_destruct(&nitf); + nitf_SubWindow_destruct(&subWindow); + nitf_DownSampler_destruct(&downSampler); + exit(0); + } + } + else + { + nitf_Error_init(errorObj, "Invalid down-sample method", + NITF_CTXT, NITF_ERR_INVALID_PARAMETER); + nitf_Error_fprintf(errorObj, stderr, + "Invalid down-sample method: %s\n", readArgs->downSample); + nitf_IOHandle_close(fileHandle); + nitf_ImageIO_destruct(&nitf); + nitf_SubWindow_destruct(&subWindow); + exit(0); + } + } + + /* Read sub-window */ + + if (!nitf_ImageIO_read(nitf, fileHandle, subWindow, user, &padded, errorObj)) + { + nitf_Error_print(errorObj, stderr, "Read failed"); + nitf_IOHandle_close(fileHandle); + nitf_ImageIO_destruct(&nitf); + nitf_SubWindow_destruct(&subWindow); + exit(0); + } + nitf_SubWindow_destruct(&subWindow); + + nitf_IOHandle_close(fileHandle); + + printf("Padded = %d\n", padded); + + /* Write result */ + + for (i = 0;i < readArgs->nBands;i++) + { + if ((ofd = open(argv[3+i], O_WRONLY | O_CREAT | O_TRUNC, 0666)) == -1) + { + fprintf(stderr, "Output file %d open failed\n", i); + exit(0); + } + + write(ofd, user[i], subWindowSize); + close(ofd); + } + + return 0; +} diff --git a/modules/c/nitf/tests/test_ImageIO_support.c b/modules/c/nitf/tests/test_ImageIO_support.c new file mode 100644 index 000000000..997a82d5c --- /dev/null +++ b/modules/c/nitf/tests/test_ImageIO_support.c @@ -0,0 +1,939 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +/* +* This file provides support functions for test_ImageIO_read_data and +* test_ImageIO_writePattern +*/ + +#include "test_ImageIO.h" + +/* Buffer for error messages */ + +static char buffer[TEST_NITF_IMAGE_IO_MAX_STRING+2]; + +/*====================== test_nitf_ImageIOReadConstructArgs ==================*/ + +NITFAPI(test_nitf_ImageIOConstructArgs *) test_nitf_ImageIOReadConstructArgs( + FILE *file, char **error) +{ + test_nitf_ImageIOConstructArgs *args; /* The result */ + long padValues[8]; /* Temp for pad value bytes */ + long tmpLong; /* Temp for longs */ + nitf_Uint32 i; + + args = (test_nitf_ImageIOConstructArgs *) + malloc(sizeof(test_nitf_ImageIOConstructArgs)); + if (args == NULL) + { + snprintf(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, + "Error allocating arguments structure"); + *error = buffer; + return(NULL); + } + + if (fgets(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, file) == NULL) + { + snprintf(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, + "Error reading new argument file, nRows argument"); + *error = buffer; + return(NULL); + } + if (sscanf(buffer, "%ld", &tmpLong) != 1) + { + snprintf(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, + "Error decoding new argument file, nRows argument"); + *error = buffer; + return(NULL); + } + args->nRows = tmpLong; + + if (fgets(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, file) == NULL) + { + snprintf(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, + "Error reading new argument file, nColumns argument"); + *error = buffer; + return(NULL); + } + if (sscanf(buffer, "%ld", &tmpLong) != 1) + { + snprintf(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, + "Error decoding new argument file, nColumns argument"); + *error = buffer; + return(NULL); + } + args->nColumns = tmpLong; + + if (fgets(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, file) == NULL) + { + snprintf(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, + "Error reading new argument file, nBands argument"); + *error = buffer; + return(NULL); + } + if (sscanf(buffer, "%ld", &tmpLong) != 1) + { + snprintf(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, + "Error decoding new argument file, nBands argument"); + *error = buffer; + return(NULL); + } + args->nBands = tmpLong; + + if (fgets(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, file) == NULL) + { + snprintf(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, + "Error reading new argument file, nMultiBands argument"); + *error = buffer; + return(NULL); + } + if (sscanf(buffer, "%ld", &tmpLong) != 1) + { + snprintf(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, + "Error decoding new argument file, nMultiBands argument"); + *error = buffer; + return(NULL); + } + args->nMultiBands = tmpLong; + + if (fgets(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, file) == NULL) + { + snprintf(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, + "Error reading new argument file, pixelType argument"); + *error = buffer; + return(NULL); + } + if (sscanf(buffer, "%s", args->pixelType) != 1) + { + snprintf(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, + "Error decoding new argument file, pixelType argument"); + *error = buffer; + return(NULL); + } + + if (fgets(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, file) == NULL) + { + snprintf(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, + "Error reading new argument file, nBits argument"); + *error = buffer; + return(NULL); + } + if (sscanf(buffer, "%ld", &tmpLong) != 1) + { + snprintf(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, + "Error decoding new argument file, nBits argument"); + *error = buffer; + return(NULL); + } + args->nBits = tmpLong; + if (fgets(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, file) == NULL) + { + snprintf(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, + "Error reading new argument file, nBitsActual argument"); + *error = buffer; + return(NULL); + } + if (sscanf(buffer, "%ld", &tmpLong) != 1) + { + snprintf(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, + "Error decoding new argument file, nBitsActual argument"); + *error = buffer; + return(NULL); + } + args->nBitsActual = tmpLong; + + if (fgets(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, file) == NULL) + { + snprintf(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, + "Error reading new argument file, justify argument"); + *error = buffer; + return(NULL); + } + if (sscanf(buffer, "%s", args->justify) != 1) + { + snprintf(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, + "Error decoding new argument file, justify argument"); + *error = buffer; + return(NULL); + } + + if (fgets(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, file) == NULL) + { + snprintf(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, + "Error reading new argument file, nBlksPerRow argument"); + *error = buffer; + return(NULL); + } + if (sscanf(buffer, "%ld", &tmpLong) != 1) + { + snprintf(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, + "Error decoding new argument file, nBlksPerRow argument"); + *error = buffer; + return(NULL); + } + args->nBlksPerRow = tmpLong; + + if (fgets(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, file) == NULL) + { + snprintf(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, + "Error reading new argument file, nBlksPerColumn argument"); + *error = buffer; + return(NULL); + } + if (sscanf(buffer, "%ld", &tmpLong) != 1) + { + snprintf(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, + "Error decoding new argument file, nBlksPerColumn argument"); + *error = buffer; + return(NULL); + } + args->nBlksPerColumn = tmpLong; + + if (fgets(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, file) == NULL) + { + snprintf(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, + "Error reading new argument file, nRowsPerBlk argument"); + *error = buffer; + return(NULL); + } + if (sscanf(buffer, "%ld", &tmpLong) != 1) + { + snprintf(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, + "Error decoding new argument file, nRowsPerBlk argument"); + *error = buffer; + return(NULL); + } + args->nRowsPerBlk = tmpLong; + + if (fgets(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, file) == NULL) + { + snprintf(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, + "Error reading new argument file, nColumnsPerBlk argument"); + *error = buffer; + return(NULL); + } + if (sscanf(buffer, "%ld", &tmpLong) != 1) + { + snprintf(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, + "Error decoding new argument file, nColumnsPerBlk argument"); + *error = buffer; + return(NULL); + } + args->nColumnsPerBlk = tmpLong; + + if (fgets(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, file) == NULL) + { + snprintf(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, + "Error reading new argument file, mode argument"); + *error = buffer; + return(NULL); + } + if (sscanf(buffer, "%s", args->mode) != 1) + { + snprintf(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, + "Error decoding new argument file, mode argument"); + *error = buffer; + return(NULL); + } + + if (fgets(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, file) == NULL) + { + snprintf(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, + "Error reading new argument file, compression argument"); + *error = buffer; + return(NULL); + } + if (sscanf(buffer, "%s", args->compression) != 1) + { + snprintf(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, + "Error decoding new argument file, compression argument"); + *error = buffer; + return(NULL); + } + + if (fgets(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, file) == NULL) + { + snprintf(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, + "Error reading new argument file, pad value argument"); + *error = buffer; + return(NULL); + } + + if (sscanf(buffer, "%lx %lx %lx %lx %lx %lx %lx %lx", + padValues, padValues + 1, padValues + 2, padValues + 3, + padValues + 4, padValues + 5, padValues + 6, padValues + 7) != 8) + { + snprintf(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, + "Error decoding new argument file, pad value argument"); + *error = buffer; + return(NULL); + } + + for (i = 0;i < 8;i++) + args->padValue[i] = padValues[i]; + + if (fgets(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, file) == NULL) + { + snprintf(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, + "Error reading new argument file, offset argument"); + *error = buffer; + return(NULL); + } + if (sscanf(buffer, "%ld", &tmpLong) != 1) + { + snprintf(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, + "Error decoding new argument file, offset argument"); + *error = buffer; + return(NULL); + } + args->offset = tmpLong; + + if (fgets(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, file) == NULL) + { + snprintf(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, + "Error reading new argument file pattern gen argument"); + *error = buffer; + return(NULL); + } + if (sscanf(buffer, "%s", args->dataPattern) != 1) + { + snprintf(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, + "Error decoding new argument file, pattern gen argument"); + *error = buffer; + return(NULL); + } + + return(args); +} + +/*========================= test_nitf_ImageIOReadReadArgs =====================*/ + +NITFAPI(test_nitf_ImageIOReadArgs *)test_nitf_ImageIOReadReadArgs( + FILE *file, char **error) +{ + test_nitf_ImageIOReadArgs *args; /* The result */ + nitf_Uint32 band; /* Current band */ + long tmpLong; /* Temp for longs */ + + args = (test_nitf_ImageIOReadArgs *) + malloc(sizeof(test_nitf_ImageIOReadArgs)); + if (args == NULL) + { + snprintf(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, + "Error allocating arguments structure"); + *error = buffer; + return(NULL); + } + + if (fgets(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, file) == NULL) + { + snprintf(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, + "Error reading read argument file, input name argument"); + *error = buffer; + return(NULL); + } + if (sscanf(buffer, "%s", args->name) != 1) + { + snprintf(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, + "Error decoding read argument file, input name argument"); + *error = buffer; + return(NULL); + } + + if (fgets(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, file) == NULL) + { + snprintf(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, + "Error reading read argument file, row argument"); + *error = buffer; + return(NULL); + } + if (sscanf(buffer, "%ld", &tmpLong) != 1) + { + snprintf(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, + "Error decoding read argument file, row argument"); + *error = buffer; + return(NULL); + } + args->row = tmpLong; + + if (fgets(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, file) == NULL) + { + snprintf(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, + "Error reading read argument file, nRows argument"); + *error = buffer; + return(NULL); + } + if (sscanf(buffer, "%ld", &tmpLong) != 1) + { + snprintf(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, + "Error decoding read argument file, nRows argument"); + *error = buffer; + return(NULL); + } + args->nRows = tmpLong; + if (fgets(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, file) == NULL) + { + snprintf(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, + "Error reading read argument file, rowSkip argument"); + *error = buffer; + return(NULL); + } + if (sscanf(buffer, "%ld", &tmpLong) != 1) + { + snprintf(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, + "Error decoding read argument file, rowSkip argument"); + *error = buffer; + return(NULL); + } + args->rowSkip = tmpLong; + + if (fgets(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, file) == NULL) + { + snprintf(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, + "Error reading read argument file, column argument"); + *error = buffer; + return(NULL); + } + if (sscanf(buffer, "%ld", &tmpLong) != 1) + { + snprintf(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, + "Error decoding read argument file, column argument"); + *error = buffer; + return(NULL); + } + args->column = tmpLong; + + if (fgets(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, file) == NULL) + { + snprintf(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, + "Error reading new argument file, nColumns argument"); + *error = buffer; + return(NULL); + } + if (sscanf(buffer, "%ld", &tmpLong) != 1) + { + snprintf(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, + "Error decoding new argument file, nColumns argument"); + *error = buffer; + return(NULL); + } + args->nColumns = tmpLong; + + if (fgets(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, file) == NULL) + { + snprintf(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, + "Error reading new argument file, column skip argument"); + *error = buffer; + return(NULL); + } + if (sscanf(buffer, "%ld", &tmpLong) != 1) + { + snprintf(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, + "Error decoding new argument file, columnSkip argument"); + *error = buffer; + return(NULL); + } + args->columnSkip = tmpLong; + + if (fgets(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, file) == NULL) + { + snprintf(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, + "Error reading read argument file, down-sample method argument"); + *error = buffer; + return(NULL); + } + if (sscanf(buffer, "%s", args->downSample) != 1) + { + snprintf(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, + "Error decoding read argument file, down-sample method argument"); + *error = buffer; + return(NULL); + } + + if (fgets(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, file) == NULL) + { + snprintf(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, + "Error reading new argument file, nBands argument"); + *error = buffer; + return(NULL); + } + if (sscanf(buffer, "%ld", &tmpLong) != 1) + { + snprintf(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, + "Error decoding new argument file, nBands argument"); + *error = buffer; + return(NULL); + } + args->nBands = tmpLong; + + for (band = 0;band < args->nBands;band++) + { + if (fgets(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, file) == NULL) + { + snprintf(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, + "Error reading new argument file, bands argument"); + *error = buffer; + return(NULL); + } + if (sscanf(buffer, "%ld", &tmpLong) != 1) + { + snprintf(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, + "Error decoding new argument file, bands argument"); + *error = buffer; + return(NULL); + } + args->bands[band] = tmpLong; + } + + return(args); +} + + +/*========================= test_nitf_ImageIO_mkArray ========================*/ + +NITFAPI(void *) test_nitf_ImageIO_mkArray( + test_nitf_ImageIOConstructArgs *args, char **error) +{ + nitf_Uint8 ***data; /* The result */ + nitf_Uint32 nBands; /* Actual number of bands */ + nitf_Uint32 band; /* The current band */ + nitf_Uint8 **rows; /* The row dimension */ + nitf_Uint32 row; /* The current row */ + nitf_Uint32 bytes; /* Number of bytes per pixel */ + nitf_Uint8 *cols; /* The column dimension */ + + nBands = args->nBands; + if (nBands == 0) + nBands = args->nMultiBands; + if (nBands == 0) + { + snprintf(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, "Invalid band count\n"); + *error = buffer; + return(NULL); + } + + /* Band dimension */ + + data = (nitf_Uint8 ***) NITF_MALLOC(nBands * sizeof(nitf_Uint8 **)); + if (data == NULL) + { + snprintf(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, + "Error allocating data buffer\n"); + *error = buffer; + return(NULL); + } + + /* Row dimension */ + + rows = (nitf_Uint8 **) NITF_MALLOC(nBands * (args->nRows) * sizeof(nitf_Uint8 *)); + if (rows == NULL) + { + NITF_FREE(data); + snprintf(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, + "Error allocating data buffer\n"); + *error = buffer; + return(NULL); + } + + for (band = 0;band < nBands;band++) + { + data[band] = rows + band * (args->nRows); + } + + /* Column dimension */ + + bytes = NITF_NBPP_TO_BYTES(args->nBits); + cols = (nitf_Uint8 *) NITF_MALLOC( + nBands * (args->nRows) * (args->nColumns) * bytes); + if (data == NULL) + { + NITF_FREE(data); + NITF_FREE(rows); + snprintf(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, + "Error allocating data buffer\n"); + *error = buffer; + return(NULL); + } + + for (band = 0;band < nBands;band++) + for (row = 0;row < args->nRows;row++) + { + data[band][row] = cols; + cols += args->nColumns * bytes; + } + + return((void *) data); +} + +/*========================= test_nitf_ImageIO_freeArray ======================*/ + +NITFAPI(void) test_nitf_ImageIO_freeArray(nitf_Uint8 ***data) +{ + NITF_FREE(data[0][0]); /* Columns */ + NITF_FREE(data[0]); /* Rows */ + NITF_FREE(data); /* Bands */ + return; +} + +/*========================= test_nitf_ImageIO_brcI4 ==========================*/ + +NITFAPI(void *) test_nitf_ImageIO_brcI4( + test_nitf_ImageIOConstructArgs *args, char **error) +{ + nitf_Uint32 ***data; /* The result */ + nitf_Uint32 nBands; /* Number of bands */ + nitf_Uint32 band; /* The current band */ + nitf_Uint32 row; /* The current row */ + nitf_Uint32 col; /* The current column */ + + data = (nitf_Uint32 ***) test_nitf_ImageIO_mkArray(args, error); + if (data == NULL) + return(NULL); + + nBands = args->nBands; + if (nBands == 0) + nBands = args->nMultiBands; + if (nBands == 0) + { + snprintf(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, "Invalid band count\n"); + *error = buffer; + return(NULL); + } + + for (band = 0;band < nBands;band++) + for (row = 0;row < args->nRows;row++) + for (col = 0;col < args->nColumns;col++) + data[band][row][col] = (band << 16) + (row << 8) + col; + + return((nitf_Uint8 ***) data); +} + +/*========================= test_nitf_ImageIO_brcI4 ==========================*/ +/* +* Single precision complex. The real part is band*100+row and the imaginary +* is band*100 + column. The data is allocated and indexed as doublw but loaded +* as two consecutive floats +*/ + +NITFAPI(void *) test_nitf_ImageIO_brcC8( + test_nitf_ImageIOConstructArgs *args, char **error) +{ + double ***data; /* The result */ + float *fdp; /* Float pointer to current pixel */ + float nBands; /* Number of bands */ + nitf_Uint32 band; /* The current band */ + nitf_Uint32 row; /* The current row */ + nitf_Uint32 col; /* The current column */ + + data = (double ***) test_nitf_ImageIO_mkArray(args, error); + if (data == NULL) + return(NULL); + + nBands = args->nBands; + if (nBands == 0) + nBands = args->nMultiBands; + if (nBands == 0) + { + snprintf(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, "Invalid band count\n"); + *error = buffer; + return(NULL); + } + + for (band = 0;band < nBands;band++) + for (row = 0;row < args->nRows;row++) + for (col = 0;col < args->nColumns;col++) + { + fdp = (float *) & (data[band][row][col]); + *(fdp++) = band * 100.0 + row; + *fdp = band * 100.0 + col; + } + + return((nitf_Uint8 ***) data); +} + +/*========================= test_nitf_ImageIO_bigEndian ======================*/ + +NITFAPI(int) test_nitf_ImageIO_bigEndian(void) +{ + nitf_Uint8 p8[2] = {1, 2}; /* For big-endian test */ + nitf_Uint16 *p16; /* For big-endian test */ + + p16 = (nitf_Uint16 *) p8; + return((*p16 == 0x102) ? 1 : 0); /* 0x102 => big-endian */ +} + +/*========================= test_nitf_ImageIO_fakeSubheader ==================*/ + +NITFAPI(nitf_ImageSubheader *) test_nitf_ImageIO_fakeSubheader( + test_nitf_ImageIOConstructArgs *args, char **error) +{ + nitf_ImageSubheader *subheader; /* For constructor */ + nitf_Error errorObj; /* Error object instance */ + + subheader = nitf_ImageSubheader_construct(&errorObj); + if (subheader == NULL) + { + snprintf(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, + "Error allocating image subheader\n"); + *error = buffer; + return(NULL); + } + + nitf_Field_setUint32(subheader->numRows, args->nRows, &errorObj); + nitf_Field_setUint32(subheader->numCols, args->nColumns, &errorObj); + nitf_Field_setUint32(subheader->numImageBands, args->nBands, &errorObj); + nitf_Field_setUint32(subheader->numMultispectralImageBands, + args->nMultiBands, &errorObj); + nitf_Field_setString(subheader->pixelValueType, args->pixelType, &errorObj); + nitf_Field_setUint32(subheader->numBitsPerPixel, args->nBits, &errorObj); + nitf_Field_setUint32(subheader->actualBitsPerPixel, + args->nBitsActual, &errorObj); + nitf_Field_setString(subheader->pixelJustification, args->justify, &errorObj); + nitf_Field_setUint32(subheader->numBlocksPerRow, + args->nBlksPerRow, &errorObj); + nitf_Field_setUint32(subheader->numBlocksPerCol, + args->nBlksPerColumn, &errorObj); + nitf_Field_setUint32(subheader->numPixelsPerVertBlock, + args->nRowsPerBlk, &errorObj); + nitf_Field_setUint32(subheader->numPixelsPerHorizBlock, + args->nColumnsPerBlk, &errorObj); + nitf_Field_setString(subheader->imageMode, args->mode, &errorObj); + nitf_Field_setString(subheader->imageCompression, + args->compression, &errorObj); + + return(subheader); +} + +/*========================= makeBlockPattern =================================*/ +/* + makeBlockPattern - Local function to make a pattern array from a blocking + specification string + + The pattern array is an array of strings describing the missing block + pattern to be generated by the "blocks" pattern option. The pixel value + is always 1 and the pad pixel value 0 + + The array is an array of strings, one of each row of blocks. Each string + contains on character for each block in the row. If the character is "M" + the block is missing, if it is "P" the block is present, if it is "T" the + block is present but has pad (T as in transition), + + for transition blocks the upper flef corner is set to be a pad pixel + regardless of the pattern. + + There is not a lot of checking for correctness in the spec + + The result can be NITF_FREE'd + +*/ + +char **makeBlockPattern(test_nitf_ImageIOConstructArgs *args, + char *spec, char **error) +{ + char **array; /* The result */ + nitf_Uint32 nBlkRows; /* Number of rows of blocks */ + nitf_Uint32 nBlkCols; /* Number of columns of blocks */ + size_t specLen; /* Length of the spec string */ + nitf_Uint32 i; + + specLen = strlen(spec); + nBlkRows = args->nBlksPerColumn; + nBlkCols = args->nBlksPerRow; + + array = NITF_MALLOC(sizeof(char *) * nBlkRows + specLen + 1); + if (array == NULL) + { + *error = "Error allocating pattern array\n"; + return(NULL); + } + strcpy((char *) (&(array[nBlkRows])), spec); + for (i = 0;i < nBlkRows;i++) + { + array[i] = ((char *) & (array[nBlkRows])) + (nBlkCols + 1) * i; + array[i][nBlkCols] = 0; + } + + return(array); +} + +/*========================= test_nitf_ImageIO_block ==========================*/ +/* +* Block pattern generator. The data is generated based on the blocking +* structure and a mask. The mask specifies which blocks are present and +* which are missing. For missing blocks the data is 0 for present blocks +* the data is the band number +* +* The mask is determined by the data generator tag. The tag always starts +* with "block_". The rest of the tag is the specification +* +* +* The specification is a single string composed of a value type string and the +* row strings of the desired result. The value type and each row sub-string is * seperated by an _. Each row string contains a character for each block in +* the row. If the character is "M" the block is missing, if it is "P" the +* block is present +* +* The value type string is three characters long and specifies how the value +* is generated. The strings are: +* +* BND - Value is band number + 1 +* BLK - Value is block number + band number + 1 +*/ + +/* Value type codes */ + +#define VALUE_BND 1 +#define VALUE_BLK 2 + +/* Macro to do pocessing for types (wants to be a template but this is C++ */ + +#define PATTERN_PROCESS(type) \ + { \ + type ***dataType = (type ***) data; \ + for(band=0;bandnRows;row++) \ + { \ + if(rowsLeft == 0) \ + { \ + blkRow += 1; \ + rowsLeft = rowsPerBlk; \ + } \ + blkCol = 0; \ + colsLeft = colsPerBlk; \ + transient = (pattern[blkRow][0] == 'T'); \ + present = transient || (pattern[blkRow][0] == 'P'); \ + for(col=0;colnColumns;col++) \ + { \ + if(colsLeft == 0) \ + { \ + blkCol += 1; \ + colsLeft = colsPerBlk; \ + transient = (pattern[blkRow][blkCol] == 'T'); \ + present = transient || (pattern[blkRow][blkCol] == 'P'); \ + } \ + if(present) \ + { \ + if(transient && \ + ((rowsLeft == rowsPerBlk) && (colsLeft == colsPerBlk))) \ + { \ + dataType[band][row][col] = *((type *) (args->padValue)); \ + } \ + else \ + { \ + switch(valueCode) \ + { \ + default: \ + case VALUE_BND: \ + dataType[band][row][col] = band + 1; \ + break; \ + case VALUE_BLK: \ + dataType[band][row][col] = \ + blkCol + blkRow*blksPerRow + band + 1; \ + break; \ + } \ + } \ + } \ + else \ + dataType[band][row][col] = *((type *) (args->padValue)); \ + colsLeft -= 1; \ + } \ + rowsLeft -= 1; \ + } \ + } \ + } + +NITFAPI(void *) test_nitf_ImageIO_block( + test_nitf_ImageIOConstructArgs *args, char **error) +{ + nitf_Uint8 ***data; /* The result */ + char **pattern; /* Block mask pattern */ + nitf_Uint32 nBands; /* Number of bands */ + nitf_Uint32 band; /* The current band */ + nitf_Uint32 bytes; /* Number of bytes per pixel */ + nitf_Uint32 blksPerRow; /* Number of blocks/row */ + nitf_Uint32 rowsPerBlk; /* Number of rows/block */ + nitf_Uint32 colsPerBlk; /* Number of columns/block */ + nitf_Uint32 valueCode; /* Output pixel value type code */ + char valueTypeStr[4]; /* Value type string from specification */ + nitf_Uint32 rowsLeft; /* Number of rows left in this block */ + nitf_Uint32 colsLeft; /* Number of columnsleft in this block */ + nitf_Uint32 blkRow; /* The current block row */ + nitf_Uint32 blkCol; /* The current block column */ + int present; /* Current block present if true */ + int transient; /* Current block transient if true */ + nitf_Uint32 row; /* The current row */ + nitf_Uint32 col; /* The current column */ + + data = (nitf_Uint8 ***) test_nitf_ImageIO_mkArray(args, error); + if (data == NULL) + return(NULL); + + pattern = makeBlockPattern(args, &(args->dataPattern[11]), error); + memmove(valueTypeStr, &(args->dataPattern[7]), 3); + valueTypeStr[3] = 0; + if (pattern == NULL) + return(NULL); + + nBands = args->nBands; + if (nBands == 0) + nBands = args->nMultiBands; + if (nBands == 0) + { + snprintf(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, "Invalid band count\n"); + *error = buffer; + return(NULL); + } + + blksPerRow = args->nBlksPerRow; + rowsPerBlk = args->nRowsPerBlk; + colsPerBlk = args->nColumnsPerBlk; + + bytes = NITF_NBPP_TO_BYTES(args->nBits); + if (strcmp(valueTypeStr, "BND") == 0) + valueCode = VALUE_BND; + else if (strcmp(valueTypeStr, "BLK") == 0) + valueCode = VALUE_BLK; + else + { + snprintf(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, "Invalid value type\n"); + *error = buffer; + return(NULL); + } + + if (bytes == 1) + PATTERN_PROCESS(nitf_Uint8) + else if (bytes == 2) + PATTERN_PROCESS(nitf_Uint16) + else if (bytes == 4) + PATTERN_PROCESS(nitf_Uint32) + else if (bytes == 8) + PATTERN_PROCESS(nitf_Uint64) + else + { + snprintf(buffer, TEST_NITF_IMAGE_IO_MAX_STRING, "Invalid byte count\n"); + *error = buffer; + return(NULL); + } + return(data); +} diff --git a/modules/c/nitf/tests/test_ImageIO_writePattern.c b/modules/c/nitf/tests/test_ImageIO_writePattern.c new file mode 100644 index 000000000..98a0c3d26 --- /dev/null +++ b/modules/c/nitf/tests/test_ImageIO_writePattern.c @@ -0,0 +1,184 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +/* +* Image sement data generator. +* +* writeImagePattern writes the data part of an image segment. This includes +* the mask header and masks if specified. The layout of the data is defined +* by a test vector. +* +* The command line call is: +* +* test_nitf_ImageIO_writePattern vector output +* +* The first argument is the test vector filename and the second is the +* output file +* +* The actual data is generated by one of several schemes: +* +* bcrI4 - Pixel encodes pixel band, row, and column as an I4 +* +* +*/ + +#include "test_ImageIO.h" +#include "nitf/ImageSubheader.h" +#include "nitf/ImageIO.h" + +#define NUM_BANDS_MAX 50 + +int main(int argc, char *argv[]) +{ + FILE *vector; /* File stream for input vector */ + /* Arguments for new */ + test_nitf_ImageIOConstructArgs *newArgs; + /* Arguments for read */ + test_nitf_ImageIOReadArgs *readArgs; + char *errorStr; /* Error string */ + + nitf_ImageSubheader *subheader; /* Subheader for ImageIO constructor */ + nitf_IOHandle io; /* Handle for output */ + nitf_Error error; /* Error object */ + nitf_ImageIO *image; /* ImageIO for image */ + nitf_Uint8 *user[NUM_BANDS_MAX]; /* User buffer for write rows */ + nitf_Uint8 ***data; /* Generated data [band][row][col] */ + nitf_Uint32 band; /* Current band */ + nitf_Uint32 row; /* Current row */ + nitf_Uint32 col; /* Current column*/ + + if (argc < 3) + { + fprintf(stderr, "Not enough arguments\n"); + exit(-1); + } + + vector = fopen(argv[1], "r"); + if (vector == NULL) + { + fprintf(stderr, "Error opening vector file %s\n", argv[1]); + exit(-1); + } + + newArgs = test_nitf_ImageIOReadConstructArgs(vector, &errorStr); + if (newArgs == NULL) + { + fprintf(stderr, "%s\n", errorStr); + return(-1); + } + + fclose(vector); + + /* Create a fake image subheader to give to ImageIO constructor */ + + subheader = test_nitf_ImageIO_fakeSubheader(newArgs, &errorStr); + if (subheader == NULL) + { + fprintf(stderr, "%s", error); + return(-1); + } + + /* Create Image */ + + if (strcmp(newArgs->dataPattern, "brcI4") == 0) + { + data = (nitf_Uint8 ***) test_nitf_ImageIO_brcI4(newArgs, &errorStr); + if (data == NULL) + { + fprintf(stderr, "%s\n", errorStr); + exit(-1); + } + } + else if (strcmp(newArgs->dataPattern, "brcC8") == 0) + { + data = (nitf_Uint8 ***) test_nitf_ImageIO_brcC8(newArgs, &errorStr); + if (data == NULL) + { + fprintf(stderr, "%s\n", errorStr); + exit(-1); + } + } + else + { + fprintf(stderr, "Invalid pattern method %s\n"); + exit(-1); + } + + /* Create output file */ + + io = nitf_IOHandle_create(argv[2], + NITF_ACCESS_WRITEONLY, NITF_CREATE | NITF_TRUNCATE, &error); + if (NITF_INVALID_HANDLE(io)) + { + nitf_Error_print(&error, stderr, "Error creating output file"); + exit(1); + } + + /* Create the ImageIO structure */ + + /* What about segment length in write ?? */ + + image = nitf_ImageIO_construct(subheader, 0, 0, NULL, NULL, &error); + if (image == NULL) + { + nitf_Error_print(&error, stderr, "Error creating ImageIO"); + exit(1); + } + + /* Setup for write */ + + nitf_ImageIO_setPadPixel(image, newArgs->padValue, + NITF_NBPP_TO_BYTES(newArgs->nBits)); + + if (nitf_ImageIO_writeSequential(image, io, &error) == 0) + { + nitf_Error_print(&error, stderr, "Error creating ImageIO"); + exit(1); + } + + /* Write rows */ + + for (row = 0;row < newArgs->nRows;row++) + { + for (band = 0;band < newArgs->nBands;band++) + user[band] = (nitf_Uint8 *) & (data[band][row][0]); + if (!nitf_ImageIO_writeRows(image, io, 1, user, &error)) + { + nitf_Error_print(&error, stderr, "Writing rows"); + exit(1); + } + } + + if (!nitf_ImageIO_writeDone(image, io, &error)) + { + nitf_Error_print(&error, stderr, "Writing rows"); + exit(1); + } + + /* Destroy things */ + + test_nitf_ImageIO_freeArray(data); + nitf_ImageIO_destruct(&image); + nitf_IOHandle_close(io); + exit(0); +} + diff --git a/modules/c/nitf/tests/test_add_masks.c b/modules/c/nitf/tests/test_add_masks.c new file mode 100644 index 000000000..41531ae09 --- /dev/null +++ b/modules/c/nitf/tests/test_add_masks.c @@ -0,0 +1,458 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +/* + Test program to add block and pad masks to the image segments of a NITF file + + This program reads a input NITF file and writes a new file with block and + pad masks added to each image segment. Only image segments are written + + The data for the image segments is read into memory so the file can't be + super big. + + The calling sequence is: + + test_add_mask inputFile outputFile + + The program can also remove a mask: + + test_add_mask [-r] [-p padValue] inputFile outputFile + + The -r switch causes the program to remove the mask + + The -p padValue switch allows the user to specify the pad pixel + value. The pad value is a hex string (with leading 0x) which gives + the pad value in big endian format. i.e., for 2 byte pixels: + + -p 0x1122 + + The value is usd for all image segments should be long enough for the + longest pixel value in any image segment. + + The -p and -r options are mutually exclusive +*/ + +#include + +/* This structure controls needed information about each iamge segment */ + +#define MAX_PAD 40 + +typedef struct _imgInfo +{ + nitf_Uint32 index; /* Segment index */ + nitf_ImageSegment *seg; /* Image segment object */ + nitf_ImageSubheader *subhdr; /* Image subheader object */ + nitf_Uint32 nBands; /* Number of bands */ + nitf_Uint32 bytes; /* Bytes/pixel */ + size_t imgSize; /* Size of each band in bytes */ + nitf_Uint8 padValue[MAX_PAD]; /* Pad value */ + nitf_Uint8 **buffers; /* Buffers containing the data */ + nitf_ImageWriter *imgWriter; /* Image writer for segment */ + nitf_ImageSource *imgSource; /* Image source for segment */ +} +imgInfo; + +/* Local function declarations (definitions at the end) */ + +NITF_BOOL readImageSegment(imgInfo *img, nitf_Reader *reader, nitf_Error *error); + +NITF_BOOL makeImageSource(imgInfo *img, nitf_Writer *writer, nitf_Error *error); + +NITF_BOOL decodePadValue(imgInfo *info, + char *string, nitf_Uint8 *value, nitf_Error *error); + +int main(int argc, char *argv[]) +{ + char *inFile; /* Input filename */ + char *outFile; /* Output filename */ + char *compCode; /* Compression code NC or NM */ + char *padValueString = NULL; /* Pad value string */ + nitf_Reader *reader; /* Reader object */ + nitf_Record *record; /* Record used for input and output */ + imgInfo *imgs; /* Image segment information */ + nitf_FileHeader *fileHdr; /* File header */ + nitf_Uint32 numImages; /* Total number of image segments */ + nitf_ListIterator imgIter; /* Image segment list iterator */ + nitf_IOHandle in; /* Input I/O handle */ + nitf_IOHandle out; /* Output I/O handle */ + nitf_Writer *writer; /* Writer object for output */ + static nitf_Error errorObj; /* Error object for messages */ + nitf_Error *error; /* Pointer to the error object */ + int i; + + error = &errorObj; + + compCode = "NM"; + if (argc == 3) + { + inFile = argv[1]; + outFile = argv[2]; + } + else if (argc == 4) + { + if (strcmp(argv[1], "-r") != 0) + { + fprintf(stderr, + "Usage %s [-r] [-p padValue] inputFile outputFile\n", argv[0]); + exit(EXIT_FAILURE); + } + inFile = argv[2]; + outFile = argv[3]; + compCode = "NC"; + } + else if (argc == 5) + { + if (strcmp(argv[1], "-p") != 0) + { + fprintf(stderr, + "Usage %s [-r] [-p padValue] inputFile outputFile\n", argv[0]); + exit(EXIT_FAILURE); + } + inFile = argv[3]; + outFile = argv[4]; + padValueString = argv[2]; + } + else + { + fprintf(stderr, "Usage %s [-r] inputFile outputFile\n", argv[0]); + exit(EXIT_FAILURE); + } + + /* Get the input record */ + + in = nitf_IOHandle_create(inFile, + NITF_ACCESS_READONLY, NITF_OPEN_EXISTING, error); + if (NITF_INVALID_HANDLE(in)) + { + nitf_Error_print(error, stderr, "Error opening input "); + exit(EXIT_FAILURE); + } + + reader = nitf_Reader_construct(error); + if (!reader) + { + nitf_Error_print(error, stderr, "Error creating reader "); + exit(EXIT_FAILURE); + } + + record = nitf_Reader_read(reader, in, error); + if (!record) + { + nitf_Error_print(error, stderr, "Error reading input "); + exit(EXIT_FAILURE); + } + fileHdr = record->header; + + nitf_Field_get(fileHdr->numImages, + &numImages, NITF_CONV_UINT, NITF_INT32_SZ, error); + + /* Get information about all image segments and set-up for write */ + + imgs = (imgInfo *) NITF_MALLOC(numImages * sizeof(imgInfo)); + if (imgs == NULL) + { + nitf_Error_print(error, stderr, "Error allocating image info "); + exit(EXIT_FAILURE); + } + + for (i = 0;i < numImages;i++) + { + imgs[i].index = i; + imgIter = nitf_List_at(record->images, i); + imgs[i].seg = (nitf_ImageSegment *) nitf_ListIterator_get(&imgIter); + if (!imgs[i].seg) + { + fprintf(stderr, "No Image segment in file\n"); + exit(EXIT_FAILURE); + } + imgs[i].subhdr = imgs[i].seg->subheader; + + if (padValueString != NULL) + { + if (!decodePadValue(&(imgs[i]), padValueString, imgs[i].padValue, error)) + { + nitf_Error_print(error, stderr, "Error allocating image info "); + exit(EXIT_FAILURE); + } + } + else + memset(imgs[i].padValue, 0, MAX_PAD); + } + + /* Read all of the image data into buffers */ + + for (i = 0;i < numImages;i++) + if (!readImageSegment(&(imgs[i]), reader, error)) + { + nitf_Error_print(error, stderr, "Error reading image segment "); + exit(EXIT_FAILURE); + } + + /* Set compression type to NM or NC (has to happen afetr read) */ + + for (i = 0;i < numImages;i++) + { + + if (!nitf_ImageSubheader_setCompression(imgs[i].subhdr, compCode, "", error)) + { + nitf_Error_print(error, stderr, "No DE segment in file "); + exit(EXIT_FAILURE); + } + } + + /* Create output */ + + out = nitf_IOHandle_create(outFile, NITF_ACCESS_WRITEONLY, NITF_CREATE, error); + if (NITF_INVALID_HANDLE(out)) + { + nitf_Error_print(error, stderr, "Could not create output file "); + exit(EXIT_FAILURE); + } + + /* Setup write and write */ + + writer = nitf_Writer_construct(error); + if (writer == NULL) + { + nitf_Error_print(error, stderr, "Write setup failed "); + exit(EXIT_FAILURE); + } + + if (!nitf_Writer_prepare(writer, record, out, error)) + { + nitf_Error_print(error, stderr, "Write setup failed "); + exit(EXIT_FAILURE); + } + + for (i = 0;i < numImages;i++) + if (!makeImageSource(&(imgs[i]), writer, error)) + { + nitf_Error_print(error, stderr, "Write setup failed "); + exit(EXIT_FAILURE); + } + + /* Set pad pixel if padValue string is not NULL */ + + if (padValueString != NULL) + for (i = 0;i < numImages;i++) + { + } + + if (!nitf_Writer_write(writer, error)) + { + nitf_Error_print(error, stderr, "Write error "); + exit(EXIT_FAILURE); + } + + + /* Clean-up */ + + nitf_Record_destruct(&record); + nitf_IOHandle_close(out); + return 0; + +} + +/* + Read Image segment - Read the image segment image data + + All of the information accept the handle is in the imgInfo + + True returned on success +*/ + +NITF_BOOL readImageSegment(imgInfo *img, nitf_Reader *reader, nitf_Error *error) +{ + nitf_Uint32 nBits; /* Bits/pixel */ + nitf_Uint32 nBands; /* Number of bands */ + nitf_Uint32 xBands; /* Number of extended bands */ + nitf_Uint32 nRows; /* Number of rows */ + nitf_Uint32 nColumns; /* Number of columns */ + size_t subimageSize; /* Image band size in bytes */ + nitf_SubWindow *subimage; /* Sub-image object specifying full image */ + nitf_DownSampler *pixelSkip; /* Downsample for sub-window */ + nitf_Uint32 *bandList; /* List of bands for read */ + nitf_Uint32 band; /* Current band */ + nitf_Uint8 **buffers; /* Read buffer one/band */ + /* Image reader */ + nitf_ImageReader *deserializer; + int padded; /* Argument for read */ + int i; + + + /* Get dimension and band info */ + + nitf_Field_get(img->subhdr->numBitsPerPixel, + &nBits, NITF_CONV_UINT, NITF_INT32_SZ, error); + nitf_Field_get(img->subhdr->numImageBands, + &nBands, NITF_CONV_UINT, NITF_INT32_SZ, error); + nitf_Field_get(img->subhdr->numMultispectralImageBands, + &xBands, NITF_CONV_UINT, NITF_INT32_SZ, error); + nBands += xBands; + nitf_Field_get(img->subhdr->numRows, + &nRows, NITF_CONV_UINT, NITF_INT32_SZ, error); + nitf_Field_get(img->subhdr->numCols, + &nColumns, NITF_CONV_UINT, NITF_INT32_SZ, error); + img->bytes = NITF_NBPP_TO_BYTES(nBits); + subimageSize = nRows * nColumns * img->bytes; + img->imgSize = subimageSize; + + + /* Setup sub-window */ + + subimage = nitf_SubWindow_construct(error); + if (subimage == NULL) + return(NITF_FAILURE); + + bandList = (nitf_Uint32 *) NITF_MALLOC(sizeof(nitf_Uint32 *) * nBands); + if (bandList == NULL) + return(NITF_FAILURE); + + subimage->startCol = 0; + subimage->startRow = 0; + subimage->numRows = nRows; + subimage->numCols = nColumns; + for (band = 0;band < nBands;band++) + bandList[band] = band; + subimage->bandList = bandList; + subimage->numBands = nBands; + + pixelSkip = nitf_PixelSkip_construct(1, 1, error); + if (pixelSkip == NULL) + return(NITF_FAILURE); + + if (!nitf_SubWindow_setDownSampler(subimage, pixelSkip, error)) + return(NITF_FAILURE); + + /* Set-up buffers (one/band) */ + + buffers = (nitf_Uint8 **) NITF_MALLOC(nBands * sizeof(nitf_Uint8*)); + if (buffers == NULL) + return(NITF_FAILURE); + + for (i = 0;i < nBands;i++) + { + buffers[i] = (nitf_Uint8 *) malloc(subimageSize); + if (buffers[i] == NULL) + return(NITF_FAILURE); + } + + deserializer = nitf_Reader_newImageReader(reader, img->index, error); + if (deserializer == NULL) + return(NITF_FAILURE); + + if (!nitf_ImageReader_read(deserializer, subimage, buffers, &padded, error)) + return(NITF_FAILURE); + + img->nBands = nBands; + img->buffers = buffers; + return(NITF_SUCCESS); +} + +NITF_BOOL makeImageSource(imgInfo *img, nitf_Writer *writer, nitf_Error *error) +{ + nitf_ImageSource *source; /* Image source for image writer */ + nitf_BandSource *bandSource; /* Current band source */ + int i; + + img->imgWriter = nitf_Writer_newImageWriter(writer, img->index, error); + source = nitf_ImageSource_construct(error); + if (source == NULL) + return(NITF_FAILURE); + + for (i = 0;i < img->nBands;i++) + { + bandSource = nitf_MemorySource_construct((char *) (img->buffers[i]), + img->imgSize, (nitf_Off) 0, 0, 0, error); + if (!bandSource) + return(NITF_FAILURE); + + if (!nitf_ImageSource_addBand(source, bandSource, error)) + return(NITF_FAILURE); + } + + img->imgSource = source; + + if (!nitf_ImageWriter_attachSource(img->imgWriter, source, error)) + return(NITF_FAILURE); + + nitf_ImageIO_setPadPixel(img->imgWriter->imageBlocker, + img->padValue, img->bytes); + + return(NITF_SUCCESS); +} + +NITF_BOOL decodePadValue(imgInfo *info, + char *string, nitf_Uint8 *value, nitf_Error *error) +{ + char *str; /* Pointer into the string */ + size_t len; /* Current length of the value string */ + nitf_Uint32 nValues; /* Number of byte values in pad value */ + nitf_Uint32 i; + + str = string; + len = strlen(str); + nValues = (len - 2) / 2; + + if ( + (len <= 2) /* Must be more that 2 characters */ + || ((len & 1) != 0) /* String length must be even */ + || (nValues > (MAX_PAD - 1)) /* Specifcation is too long */ + ) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_INVALID_PARAMETER, + "Error decoding pad value: %s", string); + return (NITF_FAILURE); + } + + if ((str[0] != '0') || ((str[1] != 'x') && (str[1] != 'X'))) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_INVALID_PARAMETER, + "Error decoding pad value: %s", string); + return (NITF_FAILURE); + } + str += 2; + len -= 2; + + for (i = 0;i < nValues;i++) + { + int currentByte; /* Current byte in value */ + char val[3]; /* Current byte as characters */ + + val[0] = tolower(*str); + str += 1; + val[1] = tolower(*str); + str += 1; + val[2] = 0; + if (sscanf(val, "%x", ¤tByte) != 1) + { + nitf_Error_initf(error, NITF_CTXT, NITF_ERR_INVALID_PARAMETER, + "Error decoding pad value: %s", string); + return (NITF_FAILURE); + } + *(value++) = currentByte; + } + + return(NITF_SUCCESS); +} + diff --git a/modules/c/nitf/tests/test_atoi.c b/modules/c/nitf/tests/test_atoi.c new file mode 100644 index 000000000..0dff3c5e1 --- /dev/null +++ b/modules/c/nitf/tests/test_atoi.c @@ -0,0 +1,55 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + + +#include + +#define BIG "3000000000" +#define SMALLER "300000000" + +int main(int argc, char *argv[]) +{ + nitf_Int32 i32; + nitf_Uint32 u32; + + i32 = NITF_ATO32(BIG); + u32 = NITF_ATO32(BIG); + + printf("First test of NITF_ATO32 i32 %d u32 %u\n", i32, u32); + + i32 = NITF_ATO32(SMALLER); + u32 = NITF_ATO32(SMALLER); + + printf("Second test of NITF_ATO32 i32 %d u32 %u\n", i32, u32); + + i32 = NITF_ATOU32(BIG); + u32 = NITF_ATOU32(BIG); + + printf("First test of NITF_ATOU32 i32 %d u32 %u\n", i32, u32); + + i32 = NITF_ATOU32(SMALLER); + u32 = NITF_ATOU32(SMALLER); + + printf("Second test of NITF_ATOU32 i32 %d u32 %u\n", i32, u32); + + exit(0); +} diff --git a/modules/c/nitf/tests/test_blank.ntf b/modules/c/nitf/tests/test_blank.ntf new file mode 100644 index 000000000..a4b88a318 --- /dev/null +++ b/modules/c/nitf/tests/test_blank.ntf @@ -0,0 +1 @@ +NITF02.1003BF01123456789020070101000000File title Blank file, file header only ****************************************U121234567890112123456789012345678901212345678123411234567812345678901234567890123456789012345678901231123456789012345678901234567890123456789011234567812345678901234512345123450AAA123456789012345678901234(000) 000-0000****0000000003880003880000000000000000000000000000 diff --git a/modules/c/nitf/tests/test_clevel.c b/modules/c/nitf/tests/test_clevel.c new file mode 100644 index 000000000..a119f038a --- /dev/null +++ b/modules/c/nitf/tests/test_clevel.c @@ -0,0 +1,549 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + +int gAlerts = 1; + +typedef enum _CLEVEL +{ + CLEVEL_CHECK_FAILED = 0, + CLEVEL_03, + CLEVEL_05, + CLEVEL_06, + CLEVEL_07, + CLEVEL_09, + CLEVEL_UNKNOWN +} CLEVEL; + +#define TRY_IT(X) if (! X ) return CLEVEL_CHECK_FAILED +typedef CLEVEL (*CLEVEL_CHECK_PTR)(nitf_Record*, nitf_Error*); + + +void showMessage(const char* format, ...) +{ + if (gAlerts) + { + va_list ap; + va_start(ap, format); + + vfprintf(stdout, format, ap); + va_end(ap); + } + +} + +CLEVEL checkILOC(nitf_ImageSubheader* subhdr, nitf_Error* error) +{ + char iloc[NITF_ILOC_SZ + 1]; + char num[6]; + int rowCoord, colCoord; + int rowExtent, colExtent; + int nrows, ncols; + TRY_IT( nitf_Field_get(subhdr->imageLocation, + iloc, NITF_CONV_STRING, NITF_ILOC_SZ + 1, error) ); + num[5] = 0; + memcpy(num, iloc, 5); + rowCoord = atoi(num); + memcpy(num, &iloc[5], 5); + colCoord = atoi(num); + + subhdr->numRows; + subhdr->numCols; + + TRY_IT( nitf_Field_get(subhdr->numRows, + &nrows, NITF_CONV_INT, sizeof(int), error) ); + TRY_IT( nitf_Field_get(subhdr->numCols, + &ncols, NITF_CONV_INT, sizeof(int), error) ); + + rowExtent = rowCoord + nrows; + colExtent = colCoord + ncols; + + if (rowExtent <= 2047 && colExtent <= 2047) + return CLEVEL_03; + + if (rowExtent <= 8191 && colExtent <= 8191) + return CLEVEL_05; + + if (rowExtent <= 65535 && colExtent <= 65535) + return CLEVEL_06; + + if (rowExtent <= 99999999 && colExtent <= 99999999) + return CLEVEL_07; + + else return CLEVEL_09; + +} + +CLEVEL checkCCSExtent(nitf_Record* record, nitf_Error* error) +{ + int clevel = CLEVEL_03; + + nitf_ListIterator it = nitf_List_begin(record->images); + nitf_ListIterator end = nitf_List_end(record->images); + int i = 0; + while ( nitf_ListIterator_notEqualTo(&it, &end) ) + { + nitf_ImageSegment* imageSegment = (nitf_ImageSegment*)nitf_ListIterator_get(&it); + int result = checkILOC(imageSegment->subheader, error); + if ( result == CLEVEL_CHECK_FAILED ) return result; + if ( result > clevel ) + { + showMessage("Image [%d]'s CCS elevated CLEVEL\n", i); + clevel = result; + } + ++i; + nitf_ListIterator_increment(&it); + } + + return clevel; +} + + +CLEVEL checkFileSize(nitf_Record* record, nitf_Error* error) +{ + nitf_Int64 fl; + TRY_IT( nitf_Field_get(record->header->fileLength, + &fl, NITF_CONV_INT, 8, error )); + if (fl <= 52428799) + { + return CLEVEL_03; + } + if (fl <= 1073741823) + { + return CLEVEL_05; + } + if (fl <= 2147483647) + { + return CLEVEL_06; + } + if (fl <= NITF_INT64(10737418239)) + { + return CLEVEL_07; + } + return CLEVEL_09; +} + + + +CLEVEL checkImage(nitf_ImageSubheader* subhdr, nitf_Error* error) +{ + int nrows, ncols; + + TRY_IT( nitf_Field_get(subhdr->numRows, + &nrows, NITF_CONV_INT, sizeof(int), error) ); + TRY_IT( nitf_Field_get(subhdr->numCols, + &ncols, NITF_CONV_INT, sizeof(int), error) ); + + + if (nrows <= 2047 && ncols <= 2047) + return CLEVEL_03; + + if (nrows <= 8191 && ncols <= 8191) + return CLEVEL_05; + + if (nrows <= 65535 && ncols <= 65535) + return CLEVEL_06; + + if (nrows <= 99999999 && ncols <= 99999999) + return CLEVEL_07; + + else return CLEVEL_09; + +} + + + + +CLEVEL checkImageSize(nitf_Record* record, nitf_Error* error) +{ + int clevel = CLEVEL_03; + + nitf_ListIterator it = nitf_List_begin(record->images); + nitf_ListIterator end = nitf_List_end(record->images); + int i = 0; + while ( nitf_ListIterator_notEqualTo(&it, &end) ) + { + nitf_ImageSegment* imageSegment = + (nitf_ImageSegment*)nitf_ListIterator_get(&it); + int result = checkImage(imageSegment->subheader, error); + if ( result == CLEVEL_CHECK_FAILED ) return result; + if ( result > clevel ) + { + showMessage("Image [%d]'s size elevated CLEVEL\n", i); + clevel = result; + } + ++i; + nitf_ListIterator_increment(&it); + } + + return clevel; +} + +CLEVEL checkImageBlock(nitf_ImageSubheader* subhdr, nitf_Error* error) +{ + + int nppbh, nppbv; + TRY_IT( nitf_Field_get(subhdr->numPixelsPerHorizBlock, + &nppbh, NITF_CONV_INT, sizeof(int), error) ); + TRY_IT( nitf_Field_get(subhdr->numPixelsPerVertBlock, + &nppbv, NITF_CONV_INT, sizeof(int), error) ); + + if (nppbh <= 0 || nppbv <= 0) + return CLEVEL_09; + + if (nppbh <= 2048 && nppbv <= 2048) + return CLEVEL_03; + + if (nppbh <= 8192 && nppbv <= 8192) + return CLEVEL_05; + + + return CLEVEL_06; +} + + + +CLEVEL checkBlockSize(nitf_Record* record, nitf_Error* error) +{ + int clevel = CLEVEL_03; + + nitf_ListIterator it = nitf_List_begin(record->images); + nitf_ListIterator end = nitf_List_end(record->images); + int i = 0; + while ( nitf_ListIterator_notEqualTo(&it, &end) ) + { + nitf_ImageSegment* imageSegment = (nitf_ImageSegment*)nitf_ListIterator_get(&it); + int result = checkImageBlock(imageSegment->subheader, error); + if ( result == CLEVEL_CHECK_FAILED ) return result; + if ( result > clevel ) + { + showMessage("Image [%d]'s size elevated CLEVEL\n", i); + clevel = result; + } + ++i; + nitf_ListIterator_increment(&it); + } + + return clevel; +} + + + +CLEVEL checkDES(nitf_Record* record, nitf_Error* error) +{ + int clevel = CLEVEL_03; + + int numdes; + TRY_IT( nitf_Field_get(record->header->numDataExtensions, + &numdes, NITF_CONV_INT, sizeof(int), error ) ); + + if (numdes > 10) + { + if (numdes <= 50) + { + clevel = CLEVEL_06; + } + if (numdes <= 100) + { + clevel = CLEVEL_07; + } + else clevel = CLEVEL_09; + } + return clevel; + +} +CLEVEL checkRGBImage(nitf_ImageSubheader* subhdr, nitf_Error* error) +{ + int clevel = CLEVEL_03; + int nbands, nbpp; + char imode = subhdr->imageMode->raw[0]; + TRY_IT( nitf_Field_get(subhdr->numImageBands, + &nbands, NITF_CONV_INT, sizeof(int), error ) ); + TRY_IT( nitf_Field_get(subhdr->numBitsPerPixel, + &nbpp, NITF_CONV_INT, sizeof(int), error ) ); + + if (nbands != 3) + { + clevel = CLEVEL_09; + } + + else if (imode != 'B' && + imode != 'P' && + imode != 'R' && + imode != 'S') + { + clevel = CLEVEL_09; + } + else + { + if (nbpp == 8) + { + /*clevel = CLEVEL_03;*/ + } + else if (nbpp == 16 || nbpp == 32) + { + clevel = CLEVEL_06; + } + else clevel = CLEVEL_09; + } + return clevel; + +} +CLEVEL checkRGBLUTImage(nitf_ImageSubheader* subhdr, nitf_Error* error) +{ + int clevel = CLEVEL_03; + int nbands, nbpp; + char imode = subhdr->imageMode->raw[0]; + TRY_IT( nitf_Field_get(subhdr->numImageBands, + &nbands, NITF_CONV_INT, sizeof(int), error ) ); + TRY_IT( nitf_Field_get(subhdr->numBitsPerPixel, + &nbpp, NITF_CONV_INT, sizeof(int), error ) ); + + + if (nbands != 1) + { + clevel = CLEVEL_09; + } + + else if (nbpp != 1 && + nbpp != 8) + { + clevel = CLEVEL_09; + } + else if (imode != 'B') + { + clevel = CLEVEL_09; + } + + return clevel; + +} +CLEVEL checkMonoImage(nitf_ImageSubheader* subhdr, nitf_Error* error) +{ + int clevel = CLEVEL_03; + int nbands, nbpp; + char imode = subhdr->imageMode->raw[0]; + TRY_IT( nitf_Field_get(subhdr->numImageBands, + &nbands, NITF_CONV_INT, sizeof(int), error ) ); + TRY_IT( nitf_Field_get(subhdr->numBitsPerPixel, + &nbpp, NITF_CONV_INT, sizeof(int), error ) ); + + if (nbands != 1) + { + clevel = CLEVEL_09; + } + + else if (nbpp != 1 && + nbpp != 8 && + nbpp != 12 && + nbpp != 16 && + nbpp != 32 && + nbpp != 64) + { + clevel = CLEVEL_09; + } + else if (imode != 'B') + { + clevel = CLEVEL_09; + } + + return clevel; + + +} + +CLEVEL checkSpecificImageAttributes(nitf_Record* record, nitf_Error* error) +{ + CLEVEL clevel = CLEVEL_03; + nitf_ListIterator it = nitf_List_begin(record->images); + nitf_ListIterator end = nitf_List_end(record->images); + int i = 0; + while ( nitf_ListIterator_notEqualTo(&it, &end) ) + { + CLEVEL result = CLEVEL_CHECK_FAILED; + char irep[ NITF_IREP_SZ + 1 ]; + nitf_ImageSegment* imageSegment = + (nitf_ImageSegment*)nitf_ListIterator_get(&it); + TRY_IT( nitf_Field_get(imageSegment->subheader->imageRepresentation, + irep, NITF_CONV_STRING, + NITF_IREP_SZ + 1, error ) ); + if (strcmp( irep, "MONO ") == 0) + { + result = checkMonoImage(imageSegment->subheader, error); + } + else if (strcmp( irep, "RGB ") == 0) + { + result = checkRGBImage(imageSegment->subheader, error); + } + else if (strcmp( irep, "RGB/LUT ") == 0) + { + result = checkRGBLUTImage(imageSegment->subheader, error); + } + else + { + nitf_Error_init(error, "Unknown IREP Clevel check failed", + NITF_CTXT, NITF_ERR_INVALID_OBJECT); + return result; + } + + if ( result == CLEVEL_CHECK_FAILED ) return result; + if (result > clevel) + { + showMessage("Image: [%d], elevated CLEVEL\n", i); + clevel = result; + } + ++i; + nitf_ListIterator_increment(&it); + + } + return clevel; + +} + + +typedef struct _ComplexityLevelCheck +{ + char* checkName; + CLEVEL_CHECK_PTR check; +} +ComplexityLevelCheck; + +static ComplexityLevelCheck checks[] = + { + { "CCS Extent", checkCCSExtent + }, + { "File Size", checkFileSize }, + { "Image Size", checkImageSize }, + { "Block Size", checkBlockSize }, + { "DES", checkDES }, + { "Image Attributes", checkSpecificImageAttributes }, + { NULL, NULL } + }; + + +NITF_BOOL measureComplexityLevel(nitf_Record* record, + CLEVEL* clevel, + nitf_Error* error) +{ + int i = 0; + int checkComplexity; + char *p = checks[0].checkName; + CLEVEL_CHECK_PTR checkToRun = checks[0].check; + *clevel = CLEVEL_03; + + while ( p != NULL ) + { + showMessage("Performing check [%s]\n", p); + + checkComplexity = (*checkToRun)(record, error); + if (checkComplexity == CLEVEL_CHECK_FAILED) + { + *clevel = checkComplexity; + return NITF_FAILURE; + } + else if (checkComplexity > *clevel) + { + showMessage("Check [%s] elevated complexity level to [%d]\n", + p, checkComplexity); + *clevel = checkComplexity; + } + ++i; + p = checks[i].checkName; + checkToRun = checks[i].check; + } + + return NITF_SUCCESS; +} + +char* clevelAsString(CLEVEL clevel) +{ + + switch (clevel) + { + case CLEVEL_03: + return "03"; + case CLEVEL_05: + return "05"; + case CLEVEL_06: + return "06"; + case CLEVEL_07: + return "07"; + case CLEVEL_09: + return "09"; + case CLEVEL_UNKNOWN: + return "Unknown"; + } + return "Error"; +} + +int main(int argc, char** argv) +{ + CLEVEL clevel; + nitf_Reader* reader; + nitf_Record* record; + nitf_IOHandle io; + nitf_Error error; + /* Check argv and make sure we are happy */ + if ( argc != 2 ) + { + printf("Usage: %s \n", argv[0]); + exit(EXIT_FAILURE); + } + + io = nitf_IOHandle_create(argv[1], NITF_ACCESS_READONLY, + NITF_OPEN_EXISTING, &error); + + if ( NITF_INVALID_HANDLE( io ) ) + { + nitf_Error_print(&error, stdout, "Exiting..."); + exit( EXIT_FAILURE ); + } + + reader = nitf_Reader_construct(&error); + if (!reader) + { + nitf_Error_print(&error, stdout, "Exiting ..."); + nitf_IOHandle_close(io); + exit( EXIT_FAILURE ); + } + + /* read the record */ + record = nitf_Reader_read(reader, io, &error ); + if (!record) + { + goto DESTROY_BLOCK; + } + + if (! measureComplexityLevel(record, &clevel, &error) ) + { + nitf_Error_print(&error, stdout, "During complexity level check ..."); + exit( EXIT_FAILURE ); + } + printf("Complexity level of file is [%s]\n", clevelAsString(clevel)); +DESTROY_BLOCK: + nitf_IOHandle_close(io); + nitf_Record_destruct(&record); + nitf_Reader_destruct(&reader); + + return 0; +} diff --git a/modules/c/nitf/tests/test_create_xmltre.c b/modules/c/nitf/tests/test_create_xmltre.c new file mode 100644 index 000000000..bf38be5e8 --- /dev/null +++ b/modules/c/nitf/tests/test_create_xmltre.c @@ -0,0 +1,778 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + + +#include + +#define FAKE_DESC "Fake. \nRemove Me" +#define DESC1 "First desc." +#define DESC2 "TRE that doesnt really do much. Just a demo." +#define PUB_DATE "March 2008" +#define VER "0.1" +#define AUTH "DP" +#define CONSTANT_PI M_PI +#define CONSTANT_C 299792458.0 +#define IND_1 1.2 +#define IND_2 2.4 +#define IND_3 3.6 +#define ATT_1 "Tom" + +/* + * This function dumps a TRE using the TRE enumerator. + * The enumerator is used to walk the fields of a TRE in order + * when the TRE enumerator is expired it will be set to NULL. + * + */ +void printTRE(nitf_TRE* tre) +{ + nitf_Error error; + nitf_Uint32 treLength; + nitf_TREEnumerator* it = NULL; + const char* treID = NULL; + + /* This is just so you know how long the TRE is */ + treLength = tre->handler->getCurrentSize(tre, &error); + + /* + * This is the name for the description that was selected to field + * this TRE by the handler. + */ + treID = nitf_TRE_getID(tre); + + printf("\n--------------- %s TRE (%d) - (%s) ---------------\n", + tre->tag, treLength, treID ? treID : "null id"); + + /* Now walk the TRE */ + it = nitf_TRE_begin(tre, &error); + + while(it && it->hasNext(&it)) + { + /* If this isn't set, it should have been an error */ + nitf_Pair* fieldPair = it->next(it, &error); + if (fieldPair) + { + printf("%s = [", fieldPair->key); + nitf_Field_print((nitf_Field *) fieldPair->data); + printf("]\n"); + } + else + nitf_Error_print(&error, stdout, "Field retrieval error"); + + } + printf("---------------------------------------------\n"); +} + +/* + * Warning! In order for this test to work properly, you MUST + * set the NITF_PLUGIN_PATH to use the XMLTRE plugin provided in + * the external/examples area! + * + * Failing to set this will cause TRE creation to fail! + * + * This test case adds a TRE called XMLTRE to the header. The user + * is *not* required to provide an XML file that can be inserted into the + * body of the TRE, which is different from another test case. + * + */ + +nitf_TRE* createXMLTRE(nitf_Error* error) +{ + /* For starters, we need to create the XMLTRE */ + nitf_TRE* tre = nitf_TRE_construct("XMLTRE", + "xmltre", /* Root element */ + error); + + if (!tre) + return NULL; + + /* Else, we will add some stuff here */ + if (!nitf_TRE_setField(tre, "/xmltre[0]/description[0]", FAKE_DESC, strlen(FAKE_DESC), error)) + goto CATCH_ERROR; + + + /* Tests out-of-order set */ + if (!nitf_TRE_setField(tre, "/xmltre[0]/description[0]", DESC1, strlen(DESC1), error)) + goto CATCH_ERROR; + + if (!nitf_TRE_setField(tre, "/xmltre[0]/description[0]/@name", ATT_1, strlen(ATT_1), error)) + goto CATCH_ERROR; + if (!nitf_TRE_setField(tre, "/xmltre[0]/description[0]/@name", ATT_1, strlen(ATT_1), error)) + goto CATCH_ERROR; + + if (!nitf_TRE_setField(tre, "/xmltre[0]/vendor[0]/publish-date[0]", PUB_DATE, strlen(PUB_DATE), error)) + goto CATCH_ERROR; + + if (!nitf_TRE_setField(tre, "/xmltre[0]/vendor[0]/version[0]", VER, strlen(VER), error)) + goto CATCH_ERROR; + + if (!nitf_TRE_setField(tre, "/xmltre[0]/vendor[0]/author[0]", AUTH, strlen(AUTH), error)) + goto CATCH_ERROR; + + if (!nitf_TRE_setField(tre, "/xmltre[0]/constants[0]/pi[0]", "3.14", strlen("3.14"), error)) + goto CATCH_ERROR; + + + if (!nitf_TRE_setField(tre, "/xmltre[0]/constants[0]/c[0]", "299792458.0", strlen("299792458.0"), error)) + goto CATCH_ERROR; + + + if (!nitf_TRE_setField(tre, "/xmltre[0]/description[1]", FAKE_DESC, strlen(FAKE_DESC), error)) + goto CATCH_ERROR; + if (!nitf_TRE_setField(tre, "/xmltre[0]/description[1]", DESC2, strlen(DESC2), error)) + goto CATCH_ERROR; + + printTRE( tre ); + + /* Ahh, but can you go back and set it now?: + if (!nitf_TRE_setField(tre, "/xmltre[1]/vendor[1]/publish-date[1]", PUB_DATE, strlen(PUB_DATE), error)) + goto CATCH_ERROR; + + + + + + if (!nitf_TRE_setField(tre, "/xmltre[1]/vendor[1]/version[1]", VER, strlen(VER), error)) + goto CATCH_ERROR; + + + */ + return tre; + + CATCH_ERROR: + + nitf_TRE_destruct(&tre); + return NULL; + +} + +nitf_Record *doRead(const char *inFile); + + +#define GET_UINT32(FIELD, DATA_PTR, ERROR) \ + success = nitf_Field_get(FIELD, DATA_PTR, NITF_CONV_UINT, NITF_INT32_SZ, ERROR); \ + if (!success) goto CATCH_ERROR; + +#define GET_UINT64(FIELD, DATA_PTR, ERROR) \ + success = nitf_Field_get(FIELD, DATA_PTR, NITF_CONV_UINT, NITF_INT64_SZ, ERROR); \ + if (!success) goto CATCH_ERROR; + +/* pass in a negative number for bandNum if you don't want a band in the name */ +char *makeBandName(const char *rootFile, const char* segment, int segmentNum, int bandNum) +{ + char *file = (char *) NITF_MALLOC(NITF_MAX_PATH); + int pos; + + /* find end slash */ + for (pos = strlen(rootFile) - 1; + pos && rootFile[pos] != '\\' && rootFile[pos] != '/'; pos--); + + if (bandNum >= 0) + NITF_SNPRINTF(file, NITF_MAX_PATH, "%s__%s_%d_band_%d", + &rootFile[pos + 1], segment, segmentNum, bandNum); + else + NITF_SNPRINTF(file, NITF_MAX_PATH, "%s__%s_%d", &rootFile[pos + 1], + segment, segmentNum); + /* remove decimals */ + for (pos = strlen(file) - 1; pos; pos--) + { + if (file[pos] == '.') + { + file[pos] = '_'; + } + } + strcat(file, ".man"); + printf("File: %s\n", file); + return file; +} + +void freeBandName(char **rootFile) +{ + if (*rootFile) + { + NITF_FREE(*rootFile); + *rootFile = NULL; + + } +} + +nitf_ImageSource *setupBands(int nbands, int imageNum, + const char *inRootFile) +{ + nitf_Error error; + int i; + nitf_BandSource *bandSource; + nitf_ImageSource *iSource = nitf_ImageSource_construct(&error); + if (!iSource) + goto CATCH_ERROR; + for (i = 0; i < nbands; i++) + { + char *inFile = makeBandName(inRootFile, "img", imageNum, i); + nitf_IOHandle sourceHandle = + nitf_IOHandle_create(inFile, NITF_ACCESS_READONLY, + NITF_OPEN_EXISTING, &error); + if (NITF_INVALID_HANDLE(sourceHandle)) + goto CATCH_ERROR; + + freeBandName(&inFile); + + bandSource = nitf_FileSource_construct(sourceHandle, + 0, 0 /*gets ignored */ , 0, + &error); + if (!bandSource) + { + goto CATCH_ERROR; + } + if (!nitf_ImageSource_addBand(iSource, bandSource, &error)) + { + goto CATCH_ERROR; + } + } + return iSource; + +CATCH_ERROR: + nitf_Error_print(&error, stderr, "While constructing image source"); + exit(EXIT_FAILURE); +} + +void doWrite(nitf_Record * record, char *inRootFile, char *outFile) +{ + nitf_ListIterator iter; + + nitf_ImageWriter *iWriter; + nitf_ImageSource *iSource; + + nitf_SegmentWriter *segmentWriter; + nitf_SegmentSource *segmentSource; + + nitf_ListIterator end; + int i; + int numImages; + int numTexts; + int numDataExtensions; + nitf_Writer *writer = NULL; + nitf_Error error; + nitf_IOHandle output_io = nitf_IOHandle_create(outFile, + NITF_ACCESS_WRITEONLY, + NITF_CREATE, + &error); + + if (NITF_INVALID_HANDLE(output_io)) + { + goto CATCH_ERROR; + } + + writer = nitf_Writer_construct(&error); + if (!writer) + { + goto CATCH_ERROR; + } + if (!nitf_Writer_prepare(writer, record, output_io, &error)) + { + goto CATCH_ERROR; + } + + if (!nitf_Field_get + (record->header->numImages, &numImages, NITF_CONV_INT, + NITF_INT32_SZ, &error)) + { + nitf_Error_print(&error, stderr, "nitf::Value::get() failed"); + numImages = 0; + } + + if (!nitf_Field_get + (record->header->numTexts, &numTexts, NITF_CONV_INT, + NITF_INT32_SZ, &error)) + { + nitf_Error_print(&error, stderr, "nitf::Value::get() failed"); + numTexts = 0; + } + + if (!nitf_Field_get + (record->header->numDataExtensions, &numDataExtensions, NITF_CONV_INT, + NITF_INT32_SZ, &error)) + { + nitf_Error_print(&error, stderr, "nitf::Value::get() failed"); + numDataExtensions = 0; + } + + if (record->images) + { + end = nitf_List_end(record->images); + for (i = 0; i < numImages; i++) + { + int nbands; + nitf_ImageSegment *imseg = NULL; + iter = nitf_List_at(record->images, i); + assert(nitf_ListIterator_notEqualTo(&iter, &end)); + + imseg = (nitf_ImageSegment *) nitf_ListIterator_get(&iter); + assert(imseg); + + if (!nitf_Field_get + (imseg->subheader->numImageBands, &nbands, NITF_CONV_INT, + NITF_INT32_SZ, &error)) + goto CATCH_ERROR; + + iWriter = nitf_Writer_newImageWriter(writer, i, NULL, &error); + if (!iWriter) + { + goto CATCH_ERROR; + } + iSource = setupBands(nbands, i, inRootFile); + if (!iSource) + goto CATCH_ERROR; + if (!nitf_ImageWriter_attachSource(iWriter, iSource, &error)) + goto CATCH_ERROR; + } + } + + if (record->texts) + { + end = nitf_List_end(record->texts); + for (i = 0; i < numTexts; i++) + { + nitf_TextSegment *textSeg = NULL; + char *inFile = NULL; + nitf_IOHandle sourceHandle; + + iter = nitf_List_at(record->texts, i); + assert(nitf_ListIterator_notEqualTo(&iter, &end)); + + textSeg = (nitf_TextSegment *) nitf_ListIterator_get(&iter); + assert(textSeg); + + segmentWriter = nitf_Writer_newTextWriter(writer, i, &error); + if (!segmentWriter) + { + goto CATCH_ERROR; + } + + /* setup file */ + inFile = makeBandName(inRootFile, "text", i, -1); + sourceHandle = + nitf_IOHandle_create(inFile, NITF_ACCESS_READONLY, + NITF_OPEN_EXISTING, &error); + if (NITF_INVALID_HANDLE(sourceHandle)) + goto CATCH_ERROR; + + freeBandName(&inFile); + + segmentSource = nitf_SegmentFileSource_construct(sourceHandle, 0, 0, &error); + if (!segmentSource) + goto CATCH_ERROR; + if (!nitf_SegmentWriter_attachSource(segmentWriter, segmentSource, &error)) + goto CATCH_ERROR; + } + } + + if (record->dataExtensions) + { + end = nitf_List_end(record->dataExtensions); + for (i = 0; i < numDataExtensions; i++) + { + nitf_DESegment *DESeg = NULL; + char *inFile = NULL; + nitf_IOHandle sourceHandle; + + iter = nitf_List_at(record->dataExtensions, i); + assert(nitf_ListIterator_notEqualTo(&iter, &end)); + + DESeg = (nitf_DESegment *) nitf_ListIterator_get(&iter); + assert(DESeg); + + segmentWriter = nitf_Writer_newDEWriter(writer, i, &error); + if (!segmentWriter) + { + goto CATCH_ERROR; + } + + /* setup file */ + inFile = makeBandName(inRootFile, "DE", i, -1); + sourceHandle = + nitf_IOHandle_create(inFile, NITF_ACCESS_READONLY, + NITF_OPEN_EXISTING, &error); + if (NITF_INVALID_HANDLE(sourceHandle)) + goto CATCH_ERROR; + + freeBandName(&inFile); + + segmentSource = nitf_SegmentFileSource_construct(sourceHandle, 0, 0, &error); + if (!segmentSource) + goto CATCH_ERROR; + if (!nitf_SegmentWriter_attachSource(segmentWriter, segmentSource, &error)) + goto CATCH_ERROR; + } + } + + if (!nitf_Writer_write(writer, &error)) + { + goto CATCH_ERROR; + } + + + /*nitf_ImageSource_destruct(&iSource);*/ + nitf_IOHandle_close(output_io); + nitf_Writer_destruct(&writer); + return; +CATCH_ERROR: + nitf_Error_print(&error, stderr, "During write"); + exit(EXIT_FAILURE); +} + +int main(int argc, char **argv) +{ + + nitf_Record *record = NULL; /* a record object */ + nitf_TRE* xmltre = NULL; + + nitf_Error error; /* error object */ + + /* Check argv and make sure we are happy */ + if (argc != 3) + { + printf("Usage: %s \n", argv[0]); + exit(EXIT_FAILURE); + } + + record = doRead(argv[1]); + + xmltre = createXMLTRE(&error); + + + + if (!xmltre) + { + nitf_Error_print(&error, stdout, "Failed to create XMLTRE"); + exit(EXIT_FAILURE); + } + + + + if (!nitf_Extensions_appendTRE(record->header->userDefinedSection, + xmltre, &error)) + { + nitf_Error_print(&error, stdout, "Failed to add XMLTRE"); + exit(EXIT_FAILURE); + } + + + doWrite(record, argv[1], argv[2]); + nitf_Record_destruct(&record); + + return 0; +} + +/* this writes the text data from a text segment to a file */ +void writeTextData(nitf_TextSegment * segment, + const char *fileName, + nitf_SegmentReader * reader, + int textNumber, nitf_Error * error) +{ + + size_t toRead; + char * buf = NULL; + char * outName = NULL; + + nitf_IOHandle file; + + toRead = (size_t)(segment->end - segment->offset); + + buf = (char*)NITF_MALLOC(toRead + 1); + if (!buf) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + return; + } + + /* get the data */ + if (nitf_SegmentReader_read(reader, buf, toRead, error) != NITF_SUCCESS) + { + /* TODO populate error */ + goto CATCH_ERROR; + } + + outName = makeBandName(fileName, "text", textNumber, -1); + file = nitf_IOHandle_create(outName, NITF_ACCESS_WRITEONLY, + NITF_CREATE, error); + freeBandName(&outName); + + if (NITF_INVALID_HANDLE(file)) + { + goto CATCH_ERROR; + } + if (!nitf_IOHandle_write(file, (const char*)buf, toRead, error)) + goto CATCH_ERROR; + nitf_IOHandle_close(file); + +CATCH_ERROR: + if (buf) NITF_FREE(buf); + return; +} + + +void manuallyWriteImageBands(nitf_ImageSegment * segment, + const char *imageName, + nitf_ImageReader * deserializer, + int imageNumber, nitf_Error * error) +{ + char *file; + nitf_Uint32 nBits, nBands, xBands, nRows, nColumns; + size_t subimageSize; + nitf_SubWindow *subimage; + unsigned int i; + int padded; + nitf_Uint8 **buffer = NULL; + nitf_Uint32 band; + nitf_Uint32 *bandList = NULL; + + NITF_TRY_GET_UINT32(segment->subheader->numBitsPerPixel, &nBits, + error); + NITF_TRY_GET_UINT32(segment->subheader->numImageBands, &nBands, error); + NITF_TRY_GET_UINT32(segment->subheader->numMultispectralImageBands, + &xBands, error); + nBands += xBands; + NITF_TRY_GET_UINT32(segment->subheader->numRows, &nRows, error); + NITF_TRY_GET_UINT32(segment->subheader->numCols, &nColumns, error); + subimageSize = nRows * nColumns * NITF_NBPP_TO_BYTES(nBits); + + buffer = (nitf_Uint8 **) malloc(8 * nBands); + band = 0; + bandList = (nitf_Uint32 *) malloc(sizeof(nitf_Uint32 *) * nBands); + + subimage = nitf_SubWindow_construct(error); + assert(subimage); + + subimage->startCol = 0; + subimage->startRow = 0; + subimage->numRows = nRows; + subimage->numCols = nColumns; + + for (band = 0; band < nBands; band++) + bandList[band] = band; + subimage->bandList = bandList; + subimage->numBands = nBands; + + assert(buffer); + for (i = 0; i < nBands; i++) + { + buffer[i] = (nitf_Uint8 *) malloc(subimageSize); + assert(buffer[i]); + } + if (!nitf_ImageReader_read + (deserializer, subimage, buffer, &padded, error)) + { + nitf_Error_print(error, stderr, "Read failed"); + goto CATCH_ERROR; + } + for (i = 0; i < nBands; i++) + { + + nitf_IOHandle toFile; + file = makeBandName(imageName, "img", imageNumber, i); + toFile = nitf_IOHandle_create(file, NITF_ACCESS_WRITEONLY, + NITF_CREATE, error); + freeBandName(&file); + if (NITF_INVALID_HANDLE(toFile)) + { + goto CATCH_ERROR; + + } + if (!nitf_IOHandle_write(toFile, + (const char *) buffer[i], + subimageSize, error)) + + { + goto CATCH_ERROR; + } + nitf_IOHandle_close(toFile); + } + + /* free buffers */ + for (i = 0; i < nBands; i++) + { + free(buffer[i]); + } + free(buffer); + free(bandList); + nitf_SubWindow_destruct(&subimage); + return; + +CATCH_ERROR: + /* free buffers */ + for (i = 0; i < nBands; i++) + { + free(buffer[i]); + } + free(buffer); + free(bandList); + nitf_Error_print(error, stderr, "Manual write failed"); + + +} +nitf_Record *doRead(const char *inFile) +{ + /* This is the error we hopefully wont receive */ + nitf_Error e; + + /* This is the reader */ + nitf_Reader *reader; + + /* This is the record of the file we are reading */ + nitf_Record *record; + + /* This is the io handle we will give the reader to parse */ + nitf_IOHandle io; + + int count = 0; + int numImages; + int numTexts; + int numDataExtensions; + + nitf_ListIterator iter; + nitf_ListIterator end; + + + nitf_ImageSegment *imageSegment = NULL; + nitf_ImageReader *deserializer = NULL; + nitf_TextSegment *textSegment = NULL; + nitf_SegmentReader *segmentReader = NULL; + + reader = nitf_Reader_construct(&e); + if (!reader) + { + nitf_Error_print(&e, stderr, "nitf::Reader::construct() failed"); + exit(EXIT_FAILURE); + } + + /* If you did, though, we'll be nice and open it for you */ + io = nitf_IOHandle_create(inFile, + NITF_ACCESS_READONLY, + NITF_OPEN_EXISTING, &e); + + /* But, oh boy, if you gave us a bad location...! */ + if (NITF_INVALID_HANDLE(io)) + { + /* You had this coming! */ + nitf_Error_print(&e, stderr, "nitf::IOHandle::create() failed"); + exit(EXIT_FAILURE); + } + + /* Read the file */ + record = nitf_Reader_read(reader, io, &e); + if (!record) + { + nitf_Error_print(&e, stderr, "nitf::Reader::read() failed"); + exit(EXIT_FAILURE); + } + + if (!nitf_Field_get + (record->header->numImages, &numImages, NITF_CONV_INT, + NITF_INT32_SZ, &e)) + { + nitf_Error_print(&e, stderr, "nitf::Field::get() failed"); + numImages = 0; + } + + if (!nitf_Field_get + (record->header->numTexts, &numTexts, NITF_CONV_INT, + NITF_INT32_SZ, &e)) + { + nitf_Error_print(&e, stderr, "nitf::Field::get() failed"); + numTexts = 0; + } + + if (!nitf_Field_get + (record->header->numDataExtensions, &numDataExtensions, NITF_CONV_INT, + NITF_INT32_SZ, &e)) + { + nitf_Error_print(&e, stderr, "nitf::Field::get() failed"); + numDataExtensions = 0; + } + + if (record->images) + { + end = nitf_List_end(record->images); + + for (count = 0; count < numImages; ++count) + { + iter = nitf_List_at(record->images, count); + if (nitf_ListIterator_equals(&iter, &end)) + { + printf("Out of bounds on iterator [%d]!\n", count); + exit(EXIT_FAILURE); + } + imageSegment = (nitf_ImageSegment *) nitf_ListIterator_get(&iter); + deserializer = nitf_Reader_newImageReader(reader, count, NULL, &e); + if (!deserializer) + { + nitf_Error_print(&e, stderr, "Couldnt spawn deserializer"); + exit(EXIT_FAILURE); + } + printf("Writing image %d... ", count); + /* Write the thing out */ + manuallyWriteImageBands(imageSegment, inFile, deserializer, count, + &e); + + nitf_ImageReader_destruct(&deserializer); + + printf("done.\n"); + /* Increment the iterator so we can continue */ + nitf_ListIterator_increment(&iter); + } + } + + + /* loop over texts and read the data to a file */ + if (record->texts) + { + end = nitf_List_end(record->texts); + + for (count = 0; count < numTexts; ++count) + { + iter = nitf_List_at(record->texts, count); + if (nitf_ListIterator_equals(&iter, &end)) + { + printf("Out of bounds on iterator [%d]!\n", count); + exit(EXIT_FAILURE); + } + textSegment = (nitf_TextSegment *) nitf_ListIterator_get(&iter); + segmentReader = nitf_Reader_newTextReader(reader, count, &e); + if (!segmentReader) + { + nitf_Error_print(&e, stderr, "Couldnt spawn deserializer"); + exit(EXIT_FAILURE); + } + printf("Writing text %d... ", count); + /* Write the thing out */ + writeTextData(textSegment, inFile, segmentReader, count, &e); + nitf_SegmentReader_destruct(&segmentReader); + + /* Increment the iterator so we can continue */ + nitf_ListIterator_increment(&iter); + } + } + + nitf_Reader_destruct(&reader); + return record; + +} diff --git a/modules/c/nitf/tests/test_debug_mem_1.c b/modules/c/nitf/tests/test_debug_mem_1.c new file mode 100644 index 000000000..b776d3f09 --- /dev/null +++ b/modules/c/nitf/tests/test_debug_mem_1.c @@ -0,0 +1,44 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + +int main(int argc, char **argv) +{ + int i; + char** str = (char**)NITF_MALLOC(sizeof(argc) * sizeof(char*)); + for (i = 0; i < argc; i++) + { + str[i] = (char*)NITF_MALLOC( strlen(argv[i]) + 1); + strcpy( str[i], argv[i]); + printf("Copied string [%d]: '%s'\n", i, str[i]); + } + for (i = 0; i < argc; i++) + { + printf("Deleting string [%d]: '%s'\n", i, str[i]); + NITF_FREE( str[i] ); + } + printf("Deleting master...\n"); + NITF_FREE( str ); + printf("Done.\n"); + return 0; +} diff --git a/modules/c/nitf/tests/test_des.c b/modules/c/nitf/tests/test_des.c new file mode 100644 index 000000000..7b7fc1fac --- /dev/null +++ b/modules/c/nitf/tests/test_des.c @@ -0,0 +1,211 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + +#define SHOW(X) printf("%s=[%s]\n", #X, ((X==0)?"(nul)":X)) +#define SHOWI(X) printf("%s=[%ld]\n", #X, X) +#define SHOWLL(X) printf("%s=[%lld]\n", #X, X) +#define SHOWRGB(X) printf("%s(R,G,B)=[%02x,%02x,%02x]\n", #X, (unsigned char) X[0], (unsigned char) X[1], (unsigned char) X[2]) +#define SHOW_VAL(X) printf("%s=[%.*s]\n", #X, ((X==0)?8:((X->raw==0)?5:X->length)), ((X==0)?"(nulptr)":((X->raw==0)?"(nul)":X->raw))) + + +/** + * This shows the TRE + * + */ +void showTRE(nitf_HashTable * ht, nitf_Pair * pair, NITF_DATA* userData, nitf_Error * error) +{ + if (pair) + { + if (pair->key) + { + nitf_ListIterator iter, end; + printf("\n--------------- %s TRE ---------------\n", + pair->key); + iter = nitf_List_begin(pair->data); + end = nitf_List_end(pair->data); + while (nitf_ListIterator_notEqualTo(&iter, &end)) + { + nitf_TRE *tre = nitf_ListIterator_get(&iter); + nitf_TRE_print(tre, error); + nitf_ListIterator_increment(&iter); + } + printf("---------------------------------------------\n"); + } + } +} + + + +/** + * This shows the security group + * + */ +void showSecurityGroup(nitf_FileSecurity * securityGroup) +{ + if (!securityGroup) + { + printf("ERROR: security group = (nul)\n"); + return; + } + + SHOW_VAL(securityGroup->classificationSystem); + SHOW_VAL(securityGroup->codewords); + SHOW_VAL(securityGroup->controlAndHandling); + SHOW_VAL(securityGroup->releasingInstructions); + SHOW_VAL(securityGroup->declassificationType); + SHOW_VAL(securityGroup->declassificationDate); + SHOW_VAL(securityGroup->declassificationExemption); + SHOW_VAL(securityGroup->downgrade); + SHOW_VAL(securityGroup->downgradeDateTime); + SHOW_VAL(securityGroup->classificationText); + SHOW_VAL(securityGroup->classificationAuthorityType); + SHOW_VAL(securityGroup->classificationAuthority); + SHOW_VAL(securityGroup->classificationReason); + SHOW_VAL(securityGroup->securitySourceDate); + SHOW_VAL(securityGroup->securityControlNumber); +} + + +/** + * This shows the DES subheader + * + */ +void showDESubheader(nitf_DESubheader * sub, nitf_Error * error) +{ + if (!sub) + { + printf("ERROR: DES subheader = (null)\n"); + return; + } + printf("* * * * * * * * * * * * * * * *\n"); + printf("DES Segment\n"); + printf("* * * * * * * * * * * * * * * *\n"); + SHOW_VAL(sub->filePartType); + SHOW_VAL(sub->typeID); + SHOW_VAL(sub->version); + SHOW_VAL(sub->securityClass); + + if (*(sub->securityClass->raw) != 'U') + showSecurityGroup(sub->securityGroup); + + SHOW_VAL(sub->overflowedHeaderType); + SHOW_VAL(sub->dataItemOverflowed); + SHOW_VAL(sub->subheaderFieldsLength); + nitf_TRE_print(sub->subheaderFields, error); + SHOWI(sub->dataLength); + + if (sub->userDefinedSection) + { + nitf_HashTable_foreach(sub->userDefinedSection->hash, + (NITF_HASH_FUNCTOR) showTRE, NULL, error); + } +} + + + +/** + * Main + * + */ +int main(int argc, char **argv) +{ + nitf_Error error; + nitf_Reader *reader; + nitf_Record *record; + nitf_IOHandle io; + int num, i; + + + if (argc < 2) + { + printf("Usage: %s [specific DES tag(s)]\n", argv[0]); + exit(EXIT_FAILURE); + } + + + io = nitf_IOHandle_create(argv[1], + NITF_ACCESS_READONLY, + NITF_OPEN_EXISTING, &error); + if (NITF_INVALID_HANDLE(io)) + { + nitf_Error_print(&error, stdout, "Exiting..."); + exit(EXIT_FAILURE); + } + + reader = nitf_Reader_construct(&error); + if (!reader) + { + nitf_Error_print(&error, stdout, "Exiting (1) ..."); + exit(EXIT_FAILURE); + } + + record = nitf_Reader_read(reader, io, &error); + if (!record) + { + nitf_Error_print(&error, stdout, "Exiting (3) ..."); + exit(EXIT_FAILURE); + } + + if (record->header->numDataExtensions) + { + nitf_ListIterator iter = nitf_List_begin(record->dataExtensions); + nitf_ListIterator end = nitf_List_end(record->dataExtensions); + + if (nitf_ListIterator_equals(&iter, &end)) + { + printf("There were no DES segments in the file.\n"); + } + + while (nitf_ListIterator_notEqualTo(&iter, &end)) + { + nitf_DESegment *segment = + (nitf_DESegment *) nitf_ListIterator_get(&iter); + + if (argc == 2) + { + showDESubheader(segment->subheader, &error); + } + else + { + for (i = 2; i < argc; ++i) + { + if (strncmp + (argv[i], segment->subheader->typeID->raw, + strlen(argv[i])) == 0) + { + showDESubheader(segment->subheader, &error); + break; + } + } + } + nitf_ListIterator_increment(&iter); + } + } + + + nitf_IOHandle_close(io); + nitf_Record_destruct(&record); + nitf_Reader_destruct(&reader); + return 0; +} diff --git a/modules/c/nitf/tests/test_des_create.c b/modules/c/nitf/tests/test_des_create.c new file mode 100644 index 000000000..58e6a5f9b --- /dev/null +++ b/modules/c/nitf/tests/test_des_create.c @@ -0,0 +1,508 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +/* + Test program for creating a DE segment + + This program creates a NITF file with a file header and a single DE Segment. + The record is cloned from an input NITF with either 0 subheaders or + n image subheaders (anything else will fail to write properly) + + The DES data and user header fields are set and the result written out as + a new NITF + + The calling sequence is: + + test_des_write inputFile outputFile + +*/ + +static const char data[] = "123456789ABCDEF0"; + +#include + +#include + + +char *makeBandName(const char *rootFile, const char* segment, int segmentNum, int bandNum) +{ + char *file = (char *) NITF_MALLOC(NITF_MAX_PATH); + int pos; + + /* find end slash */ + for (pos = strlen(rootFile) - 1; + pos && rootFile[pos] != '\\' && rootFile[pos] != '/'; pos--); + + if (bandNum >= 0) + NITF_SNPRINTF(file, NITF_MAX_PATH, "%s__%s_%d_band_%d", + &rootFile[pos + 1], segment, segmentNum, bandNum); + else + NITF_SNPRINTF(file, NITF_MAX_PATH, "%s__%s_%d", &rootFile[pos + 1],\ + segment, segmentNum); + /* remove decimals */ + for (pos = strlen(file) - 1; pos; pos--) + { + if (file[pos] == '.') + { + file[pos] = '_'; + } + } + strcat(file, ".man"); + printf("File: %s\n", file); + return file; +} + +void freeBandName(char **rootFile) +{ + if (*rootFile) + { + NITF_FREE(*rootFile); + *rootFile = NULL; + + } +} + +void manuallyWriteImageBands(nitf_ImageSegment * segment, + const char *imageName, + nitf_ImageReader * deserializer, + int imageNumber, nitf_Error * error) +{ + char *file; + nitf_Uint32 nBits, nBands, xBands, nRows, nColumns; + size_t subimageSize; + nitf_SubWindow *subimage; + unsigned int i; + int padded; + nitf_Uint8 **buffer; + nitf_Uint32 band; + nitf_Uint32 *bandList; + + NITF_TRY_GET_UINT32(segment->subheader->numBitsPerPixel, &nBits, + error); + NITF_TRY_GET_UINT32(segment->subheader->numImageBands, &nBands, error); + NITF_TRY_GET_UINT32(segment->subheader->numMultispectralImageBands, + &xBands, error); + nBands += xBands; + NITF_TRY_GET_UINT32(segment->subheader->numRows, &nRows, error); + NITF_TRY_GET_UINT32(segment->subheader->numCols, &nColumns, error); + subimageSize = nRows * nColumns * NITF_NBPP_TO_BYTES(nBits); + + printf("Image number: %d\n", imageNumber); + printf("NBANDS -> %d\n" + "XBANDS -> %d\n" + "NROWS -> %d\n" + "NCOLS -> %d\n" + "PVTYPE -> %.*s\n" + "NBPP -> %.*s\n" + "ABPP -> %.*s\n" + "PJUST -> %.*s\n" + "IMODE -> %.*s\n" + "NBPR -> %.*s\n" + "NBPC -> %.*s\n" + "NPPBH -> %.*s\n" + "NPPBV -> %.*s\n" + "IC -> %.*s\n" + "COMRAT -> %.*s\n", + nBands, + xBands, + nRows, + nColumns, + (int)segment->subheader->pixelValueType->length, + segment->subheader->pixelValueType->raw, + (int)segment->subheader->numBitsPerPixel->length, + segment->subheader->numBitsPerPixel->raw, + (int)segment->subheader->actualBitsPerPixel->length, + segment->subheader->actualBitsPerPixel->raw, + (int)segment->subheader->pixelJustification->length, + segment->subheader->pixelJustification->raw, + (int)segment->subheader->imageMode->length, + segment->subheader->imageMode->raw, + (int)segment->subheader->numBlocksPerRow->length, + segment->subheader->numBlocksPerRow->raw, + (int)segment->subheader->numBlocksPerCol->length, + segment->subheader->numBlocksPerCol->raw, + (int)segment->subheader->numPixelsPerHorizBlock->length, + segment->subheader->numPixelsPerHorizBlock->raw, + (int)segment->subheader->numPixelsPerVertBlock->length, + segment->subheader->numPixelsPerVertBlock->raw, + (int)segment->subheader->imageCompression->length, + segment->subheader->imageCompression->raw, + (int)segment->subheader->compressionRate->length, + segment->subheader->compressionRate->raw); + + + buffer = (nitf_Uint8 **) malloc(8 * nBands); + band = 0; + bandList = (nitf_Uint32 *) malloc(sizeof(nitf_Uint32 *) * nBands); + + subimage = nitf_SubWindow_construct(error); + assert(subimage); + + subimage->startCol = 0; + subimage->startRow = 0; + subimage->numRows = nRows; + subimage->numCols = nColumns; + + for (band = 0; band < nBands; band++) + bandList[band] = band; + subimage->bandList = bandList; + subimage->numBands = nBands; + + assert(buffer); + for (i = 0; i < nBands; i++) + { + buffer[i] = (nitf_Uint8 *) malloc(subimageSize); + assert(buffer[i]); + } + if (!nitf_ImageReader_read + (deserializer, subimage, buffer, &padded, error)) + { + nitf_Error_print(error, stderr, "Read failed"); + goto CATCH_ERROR; + } + for (i = 0; i < nBands; i++) + { + + nitf_IOHandle toFile; + file = makeBandName(imageName, "img", imageNumber, i); + toFile = nitf_IOHandle_create(file, NITF_ACCESS_WRITEONLY, + NITF_CREATE, error); + freeBandName(&file); + if (NITF_INVALID_HANDLE(toFile)) + { + goto CATCH_ERROR; + + } + if (!nitf_IOHandle_write(toFile, + (const char *) buffer[i], + subimageSize, error)) + + { + goto CATCH_ERROR; + } + nitf_IOHandle_close(toFile); + } + + /* free buffers */ + for (i = 0; i < nBands; i++) + { + free(buffer[i]); + } + free(buffer); + free(bandList); + nitf_SubWindow_destruct(&subimage); + return; + +CATCH_ERROR: + /* free buffers */ + for (i = 0; i < nBands; i++) + { + free(buffer[i]); + } + free(buffer); + free(bandList); + nitf_Error_print(error, stderr, "Manual write failed"); + + +} + +nitf_ImageSource *setupBands(int nbands, int imageNum, + const char *inRootFile) +{ + nitf_Error error; + int i; + nitf_BandSource *bandSource; + nitf_ImageSource *iSource = nitf_ImageSource_construct(&error); + if (!iSource) + goto CATCH_ERROR; + for (i = 0; i < nbands; i++) + { + char *inFile = makeBandName(inRootFile, "img", imageNum, i); + nitf_IOHandle sourceHandle = + nitf_IOHandle_create(inFile, NITF_ACCESS_READONLY, + NITF_OPEN_EXISTING, &error); + if (NITF_INVALID_HANDLE(sourceHandle)) + goto CATCH_ERROR; + + freeBandName(&inFile); + + bandSource = nitf_FileSource_construct(sourceHandle, + 0, 0 /*gets ignored */ , 0, + &error); + if (!bandSource) + { + goto CATCH_ERROR; + } + if (!nitf_ImageSource_addBand(iSource, bandSource, &error)) + { + goto CATCH_ERROR; + } + } + return iSource; + +CATCH_ERROR: + nitf_Error_print(&error, stderr, "While constructing image source"); + exit(EXIT_FAILURE); +} + +int main(int argc, char *argv[]) +{ + + nitf_ImageWriter *iWriter = NULL; + nitf_ImageSource *iSource = NULL; + nitf_ListIterator iter; + nitf_ListIterator end; + nitf_Reader *reader = NULL; + nitf_Record *record = NULL; + nitf_IOHandle in; + nitf_DESegment *des = NULL; + nitf_FileSecurity *security = NULL; + int bad, i; + nitf_IOHandle out; + nitf_Writer *writer = NULL; + nitf_SegmentWriter *desWriter = NULL; + nitf_SegmentSource *desData = NULL; + nitf_Error error; + int numImages; + + if (argc != 3) + { + fprintf(stderr, "Usage %s inputFile outputFile\n", argv[0]); + exit(EXIT_FAILURE); + } + + /* Get the input record */ + + in = nitf_IOHandle_create(argv[1], + NITF_ACCESS_READONLY, NITF_OPEN_EXISTING, + &error); + if (NITF_INVALID_HANDLE(in)) + { + nitf_Error_print(&error, stderr, "Error opening input "); + exit(EXIT_FAILURE); + } + + reader = nitf_Reader_construct(&error); + if (!reader) + { + nitf_IOHandle_close(in); + nitf_Error_print(&error, stderr, "Error creating reader "); + exit(EXIT_FAILURE); + } + + record = nitf_Reader_read(reader, in, &error); + if (!record) + { + nitf_Error_print(&error, stderr, "Error reading input "); + goto CATCH_ERROR; + } + + if (!nitf_Field_get + (record->header->numImages, &numImages, NITF_CONV_INT, + NITF_INT32_SZ, &error)) + { + nitf_Error_print(&error, stderr, "nitf::Value::get() failed"); + goto CATCH_ERROR; + } + + + if (record->images) + { + int count; + nitf_ImageSegment* imageSegment; + nitf_ImageReader* deserializer; + end = nitf_List_end(record->images); + + for (count = 0; count < numImages; ++count) + { + iter = nitf_List_at(record->images, count); + if (nitf_ListIterator_equals(&iter, &end)) + { + printf("Out of bounds on iterator [%d]!\n", count); + exit(EXIT_FAILURE); + } + imageSegment = (nitf_ImageSegment *) nitf_ListIterator_get(&iter); + deserializer = nitf_Reader_newImageReader(reader, count, NULL, &error); + if (!deserializer) + { + nitf_Error_print(&error, stderr, "Couldnt spawn deserializer"); + exit(EXIT_FAILURE); + } + printf("Writing image %d... ", count); + /* Write the thing out */ + manuallyWriteImageBands(imageSegment, argv[1], deserializer, count, + &error); + + nitf_ImageReader_destruct(&deserializer); + + printf("done.\n"); + /* Increment the iterator so we can continue */ + nitf_ListIterator_increment(&iter); + } + } + + + des = nitf_Record_newDataExtensionSegment(record, &error); + if (!des) + { + nitf_Record_destruct(&record); + nitf_Error_print(&error, stderr, "Error creating new DE segment "); + exit(EXIT_FAILURE); + } + + security = nitf_FileSecurity_clone(record->header->securityGroup, &error); + nitf_FileSecurity_destruct(&(des->subheader->securityGroup)); + des->subheader->securityGroup = security; + + + + des->subheader->subheaderFields = + nitf_TRE_construct("TEST DES", "TEST DES", &error); + if (!des->subheader->subheaderFields) + { + nitf_Record_destruct(&record); + nitf_Error_print(&error, stderr, "No error creating new DE segment "); + exit(EXIT_FAILURE); + } + +/* nitf_TRE_setField(des->subheader->subheaderFields, */ +/* "raw_data", */ +/* data, */ +/* 16, */ +/* &error); */ + + + nitf_TRE_setField(des->subheader->subheaderFields, + "TEST_DES_COUNT", "16", 2, &error); + nitf_TRE_setField(des->subheader->subheaderFields, + "TEST_DES_START", "065", 3, &error); + nitf_TRE_setField(des->subheader->subheaderFields, + "TEST_DES_INCREMENT", "01", 2, &error); + + nitf_Field_setString(des->subheader->NITF_DE, "DE", &error); + nitf_Field_setString(des->subheader->NITF_DESTAG, "TEST DES", &error); + nitf_Field_setString(des->subheader->NITF_DESVER, "01", &error); + nitf_Field_setString(des->subheader->NITF_DESCLAS, "U", &error); + + + out = nitf_IOHandle_create(argv[2], NITF_ACCESS_WRITEONLY, NITF_CREATE, &error); + + writer = nitf_Writer_construct(&error); + if (!writer) + { + nitf_Error_print(&error, stderr, "Write setup failed "); + goto CATCH_ERROR; + } + + if (!nitf_Writer_prepare(writer, record, out, &error)) + { + nitf_Error_print(&error, stderr, "Write setup failed "); + goto CATCH_ERROR; + } + + if (record->images) + { + end = nitf_List_end(record->images); + for (i = 0; i < numImages; i++) + { + int nbands; + nitf_ImageSegment *imseg = NULL; + iter = nitf_List_at(record->images, i); + assert(nitf_ListIterator_notEqualTo(&iter, &end)); + + imseg = (nitf_ImageSegment *) nitf_ListIterator_get(&iter); + assert(imseg); + + if (!nitf_Field_get + (imseg->subheader->numImageBands, &nbands, NITF_CONV_INT, + NITF_INT32_SZ, &error)) + goto CATCH_ERROR; + + iWriter = nitf_Writer_newImageWriter(writer, i, NULL, &error); + if (!iWriter) + { + goto CATCH_ERROR; + } + iSource = setupBands(nbands, i, argv[1]); + if (!iSource) + goto CATCH_ERROR; + if (!nitf_ImageWriter_attachSource(iWriter, iSource, &error)) + goto CATCH_ERROR; + } + } + + /* Create the DE segment */ + + + if (NITF_INVALID_HANDLE(out)) + { + nitf_Error_print(&error, stderr, "Write setup failed "); + goto CATCH_ERROR; + + } + + /* Setup write */ + + + desWriter = nitf_Writer_newDEWriter(writer, 0, &error); + if (desWriter == NULL) + { + nitf_Error_print(&error, stderr, "Write setup failed "); + goto CATCH_ERROR; + + } + + desData = nitf_SegmentMemorySource_construct(data, strlen(data), + 0, 0, 0, &error); + if (desData == NULL) + { + nitf_Error_print(&error, stderr, "Write setup failed "); + goto CATCH_ERROR; + + } + + if (!nitf_SegmentWriter_attachSource(desWriter, desData, &error)) + { + nitf_Error_print(&error, stderr, "Write setup failed "); + goto CATCH_ERROR; + } + + if (!nitf_Writer_write(writer, &error)) + { + nitf_Error_print(&error, stderr, "Write setup failed "); + goto CATCH_ERROR; + } + CATCH_ERROR: + /* Clean-up */ + if (!NITF_INVALID_HANDLE(in)) + nitf_IOHandle_close(in); + if (!NITF_INVALID_HANDLE(in)) + nitf_IOHandle_close(out); + + if (writer) + nitf_Writer_destruct(&writer); + if (record) + nitf_Record_destruct(&record); + if (reader) + nitf_Reader_destruct(&reader); + return 0; +} diff --git a/modules/c/nitf/tests/test_des_read.c b/modules/c/nitf/tests/test_des_read.c new file mode 100644 index 000000000..205984574 --- /dev/null +++ b/modules/c/nitf/tests/test_des_read.c @@ -0,0 +1,238 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +/* + Test program for reading a DE segment + + This program reads a NITF file with a file header and a single DE Segment. + + This reader is for the test_DES_example DE segment and prints out the user + header and reads and prints the user data + + The calling sequence is: + + test_DES_read inputFile + +*/ + +#include +#include "nitf/UserSegment.h" + +extern nitf_IUserSegment test_DES_example; + +int main(int argc, char *argv[]) +{ + nitf_Reader *reader; /* Reader object */ + nitf_Record *record; /* Record used for input and output */ + nitf_IOHandle in; /* Input I/O handle */ + nitf_ListIterator desIter; /* Iterator for getting the DES */ + nitf_DESegment *des; /* DE segment to read */ + nitf_DEReader *deReader; /* DE reader object for reading data */ + char *data; /* Data buffer */ + static nitf_Error errorObj; /* Error object for messages */ + nitf_Error *error; /* Pointer to the error object */ + + error = &errorObj; + + if (argc != 2) + { + fprintf(stderr, "Usage %s inputFile\n", argv[0]); + exit(EXIT_FAILURE); + } + + /* Get the input record */ + + in = nitf_IOHandle_create(argv[1], + NITF_ACCESS_READONLY, NITF_OPEN_EXISTING, + error); + if (NITF_INVALID_HANDLE(in)) + { + nitf_Error_print(error, stderr, "Error opening input "); + exit(EXIT_FAILURE); + } + + reader = nitf_Reader_construct(error); + if (!reader) + { + nitf_IOHandle_close(in); + nitf_Error_print(error, stderr, "Error creating reader "); + exit(EXIT_FAILURE); + } + + record = nitf_Reader_read(reader, in, error); + if (!record) + { + nitf_Reader_destruct(&reader); + nitf_IOHandle_close(in); + nitf_Error_print(error, stderr, "Error reading input "); + exit(EXIT_FAILURE); + } + + /* Print the user header */ + + desIter = nitf_List_at(record->dataExtensions, 0); + des = (nitf_DESegment *) nitf_ListIterator_get(&desIter); + if (!des) + { + nitf_Reader_destruct(&reader); + nitf_Record_destruct(&record); + nitf_IOHandle_close(in); + nitf_Error_print(error, stderr, "No DE segment in file "); + exit(EXIT_FAILURE); + } + + nitf_TRE_print(des->subheader->subheaderFields, error); + + /* Read the data and print it */ + + deReader = nitf_Reader_newDEReader(reader, 0, error); + if (!deReader) + { + nitf_Reader_destruct(&reader); + nitf_Record_destruct(&record); + nitf_IOHandle_close(in); + nitf_Error_print(error, stderr, "Could not create DEReader "); + exit(EXIT_FAILURE); + } + + fprintf(stdout, "Data length = %d\n", deReader->user->dataLength); + fprintf(stdout, "Virtual data length = %d\n", + deReader->user->virtualLength); + fprintf(stdout, "File offset = %lld\n", deReader->user->baseOffset); + + data = (char *) NITF_MALLOC(deReader->user->virtualLength + 2); + if (!data) + { + nitf_DEReader_destruct(&deReader); + nitf_Reader_destruct(&reader); + nitf_Record_destruct(&record); + nitf_IOHandle_close(in); + nitf_Error_print(error, stderr, "Could not allocate data buffer "); + exit(EXIT_FAILURE); + } + + if (!nitf_DEReader_read + (deReader, data, deReader->user->virtualLength, error)) + { + NITF_FREE(data); + nitf_DEReader_destruct(&deReader); + nitf_Reader_destruct(&reader); + nitf_Record_destruct(&record); + nitf_IOHandle_close(in); + nitf_Error_print(error, stderr, "Read failed "); + exit(EXIT_FAILURE); + } + + fprintf(stdout, "Data: |%s|\n", data); + + /* Try some seeks */ + + if (nitf_DEReader_seek(deReader, (nitf_Off) 4, SEEK_SET, error) == (nitf_Off) - 1) + { + NITF_FREE(data); + nitf_DEReader_destruct(&deReader); + nitf_Reader_destruct(&reader); + nitf_Record_destruct(&record); + nitf_IOHandle_close(in); + nitf_Error_print(error, stderr, "Read failed "); + exit(EXIT_FAILURE); + } + + if (!nitf_DEReader_read(deReader, data, 1, error)) + { + NITF_FREE(data); + nitf_DEReader_destruct(&deReader); + nitf_Reader_destruct(&reader); + nitf_Record_destruct(&record); + nitf_IOHandle_close(in); + nitf_Error_print(error, stderr, "Read failed "); + exit(EXIT_FAILURE); + } + + data[1] = 0; + fprintf(stdout, "Data after set seek: |%s|\n", data); + + /* + The last read advanced to position 5 so relative position10 should be + the last byte in the file + */ + + if (nitf_DEReader_seek(deReader, (nitf_Off) 10, SEEK_CUR, error) == (nitf_Off) - 1) + { + NITF_FREE(data); + nitf_DEReader_destruct(&deReader); + nitf_Reader_destruct(&reader); + nitf_Record_destruct(&record); + nitf_IOHandle_close(in); + nitf_Error_print(error, stderr, "Read failed "); + exit(EXIT_FAILURE); + } + + if (!nitf_DEReader_read(deReader, data, 1, error)) + { + NITF_FREE(data); + nitf_DEReader_destruct(&deReader); + nitf_Reader_destruct(&reader); + nitf_Record_destruct(&record); + nitf_IOHandle_close(in); + nitf_Error_print(error, stderr, "Read failed "); + exit(EXIT_FAILURE); + } + + data[1] = 0; + fprintf(stdout, "Data after current seek: |%s|\n", data); + + if (nitf_DEReader_seek(deReader, (nitf_Off) - 2, SEEK_END, error) == (nitf_Off) - 1) + { + NITF_FREE(data); + nitf_DEReader_destruct(&deReader); + nitf_Reader_destruct(&reader); + nitf_Record_destruct(&record); + nitf_IOHandle_close(in); + nitf_Error_print(error, stderr, "Read failed "); + exit(EXIT_FAILURE); + } + + if (!nitf_DEReader_read(deReader, data, 1, error)) + { + NITF_FREE(data); + nitf_DEReader_destruct(&deReader); + nitf_Reader_destruct(&reader); + nitf_Record_destruct(&record); + nitf_IOHandle_close(in); + nitf_Error_print(error, stderr, "Read failed "); + exit(EXIT_FAILURE); + } + + data[1] = 0; + fprintf(stdout, "Data after end seek: |%s|\n", data); + + /* Clean-up */ + + NITF_FREE(data); + nitf_DEReader_destruct(&deReader); + nitf_Reader_destruct(&reader); + nitf_Record_destruct(&record); + nitf_IOHandle_close(in); + return 0; + +} diff --git a/modules/c/nitf/tests/test_des_read.ntf b/modules/c/nitf/tests/test_des_read.ntf new file mode 100644 index 000000000..19118a684 --- /dev/null +++ b/modules/c/nitf/tests/test_des_read.ntf @@ -0,0 +1 @@ +NITF02.1003BF01123456789020070101000000File title Blank file, file header only ****************************************U121234567890112123456789012345678901212345678123411234567812345678901234567890123456789012345678901231123456789012345678901234567890123456789011234567812345678901234512345123450AAA123456789012345678901234(000) 000-0000****00000000062400040100000000000000102070000000160000000000000DETEST_DES 01U121234567890112123456789012345678901212345678123411234567812345678901234567890123456789012345678901231123456789012345678901234567890123456789011234567812345678901234500071606501123456789ABCDEF0 \ No newline at end of file diff --git a/modules/c/nitf/tests/test_des_write.c b/modules/c/nitf/tests/test_des_write.c new file mode 100644 index 000000000..3474a9255 --- /dev/null +++ b/modules/c/nitf/tests/test_des_write.c @@ -0,0 +1,191 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +/* + Test program for reading a DE segment + + This program writes a NITF file with a file header and a single DE Segment. + + The record is cloned from an input NITF with a single DE segment. Some + fields and the data are modified and the result written out as a new NITF + + This program uses the test_DES_example DE segment + + The calling sequence is: + + test_des_write inputFile outputFile + +*/ + +static char data[] = "123456789ABCDEF0"; + +#include + +#include +#include "nitf/UserSegment.h" + +extern nitf_IUserSegment test_DES_example; + +int main(int argc, char *argv[]) +{ + nitf_Reader *reader; /* Reader object */ + nitf_Record *record; /* Record used for input and output */ + nitf_IOHandle in; /* Input I/O handle */ + nitf_ListIterator desIter; /* Iterator for getting the DES */ + nitf_DESegment *des; /* DE segment to read */ + nitf_IOHandle out; /* Output I/O handle */ + nitf_Writer *writer; /* Writer object */ + nitf_SegmentWriter *desWriter; /* Segment writer for DE segment */ + nitf_SegmentSource *desData; /* DE segment data source */ + static nitf_Error errorObj; /* Error object for messages */ + nitf_Error *error; /* Pointer to the error object */ + + error = &errorObj; + + if (argc != 3) + { + fprintf(stderr, "Usage %s inputFile outputFile\n", argv[0]); + exit(EXIT_FAILURE); + } + + /* Get the input record */ + + in = nitf_IOHandle_create(argv[1], + NITF_ACCESS_READONLY, NITF_OPEN_EXISTING, + error); + if (NITF_INVALID_HANDLE(in)) + { + nitf_Error_print(error, stderr, "Error opening input "); + exit(EXIT_FAILURE); + } + + reader = nitf_Reader_construct(error); + if (!reader) + { + nitf_IOHandle_close(in); + nitf_Error_print(error, stderr, "Error creating reader "); + exit(EXIT_FAILURE); + } + + record = nitf_Reader_read(reader, in, error); + if (!record) + { + nitf_Reader_destruct(&reader); + nitf_IOHandle_close(in); + nitf_Error_print(error, stderr, "Error reading input "); + exit(EXIT_FAILURE); + } + + /* Get the user header */ + + desIter = nitf_List_at(record->dataExtensions, 0); + des = (nitf_DESegment *) nitf_ListIterator_get(&desIter); + if (!des) + { + nitf_Reader_destruct(&reader); + nitf_Record_destruct(&record); + nitf_IOHandle_close(in); + nitf_Error_print(error, stderr, "No DE segment in file "); + exit(EXIT_FAILURE); + } + + nitf_Reader_destruct(&reader); + nitf_IOHandle_close(in); + + /*LJW nitf_TRE_print(des->subheader->subheaderFields, error); */ + + /* Create output */ + + out = nitf_IOHandle_create(argv[2], NITF_ACCESS_WRITEONLY, NITF_CREATE, error); + if (NITF_INVALID_HANDLE(out)) + { + nitf_Record_destruct(&record); + nitf_Error_print(error, stderr, "Write setup failed "); + exit(EXIT_FAILURE); + } + + /* Setup write */ + + writer = nitf_Writer_construct(error); + if (!writer) + { + nitf_IOHandle_close(out); + nitf_Record_destruct(&record); + nitf_Error_print(error, stderr, "Write setup failed "); + exit(EXIT_FAILURE); + } + + if (!nitf_Writer_prepare(writer, record, out, error)) + { + nitf_IOHandle_close(out); + nitf_Record_destruct(&record); + nitf_Writer_destruct(&writer); + nitf_Error_print(error, stderr, "Write setup failed "); + exit(EXIT_FAILURE); + } + + desWriter = nitf_Writer_newDEWriter(writer, 0, error); + if (desWriter == NULL) + { + nitf_IOHandle_close(out); + nitf_Record_destruct(&record); + nitf_Writer_destruct(&writer); + nitf_Error_print(error, stderr, "Write setup failed "); + exit(EXIT_FAILURE); + } + + desData = nitf_SegmentMemorySource_construct(data, strlen(data), 0, 0, error); + if (desData == NULL) + { + nitf_IOHandle_close(out); + nitf_Record_destruct(&record); + nitf_Writer_destruct(&writer); + nitf_Error_print(error, stderr, "Write setup failed "); + exit(EXIT_FAILURE); + } + + if (!nitf_SegmentWriter_attachSource(desWriter, desData, error)) + { + nitf_IOHandle_close(out); + nitf_SegmentSource_destruct(&desData); + nitf_Record_destruct(&record); + nitf_Writer_destruct(&writer); + nitf_Error_print(error, stderr, "Write setup failed "); + exit(EXIT_FAILURE); + } + + if (!nitf_Writer_write(writer, error)) + { + nitf_IOHandle_close(out); + nitf_Record_destruct(&record); + nitf_Writer_destruct(&writer); + nitf_Error_print(error, stderr, "Write setup failed "); + exit(EXIT_FAILURE); + } + + /* Clean-up */ + + nitf_IOHandle_close(out); + nitf_Writer_destruct(&writer); + nitf_Record_destruct(&record); + exit(EXIT_SUCCESS); +} diff --git a/modules/c/nitf/tests/test_dll_1.c b/modules/c/nitf/tests/test_dll_1.c new file mode 100644 index 000000000..003e0d4c6 --- /dev/null +++ b/modules/c/nitf/tests/test_dll_1.c @@ -0,0 +1,107 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include +/* + * Read a file of the form + * \t\n + * Retrieval function should have the signature + * int func(void) + * + */ + +int main(int argc, char **argv) +{ + FILE* config; + char file[NITF_MAX_PATH] = ""; + char func[NITF_MAX_PATH] = ""; + + if (argc != 2) + { + printf("Usage: %s \n", + argv[0]); + exit(EXIT_FAILURE); + } + config = fopen( argv[1], "r"); + if ( !config ) + { + printf("Could not find file [%s]\n", argv[1]); + exit(EXIT_FAILURE); + } + + + while ( fscanf( config, "%s\t%s\n", file, func) != EOF ) + { + int ok; + nitf_Error error; + nitf_DLL* dll; + void (*ptr)(char**); + printf("Serving file [%s] at entry point [%s]...\n", + file, func ); + dll = nitf_DLL_construct(&error); + if (! dll ) + { + nitf_Error_print(&error, stdout, ""); + exit(EXIT_FAILURE); + } + + ok = nitf_DLL_load( dll, file, &error ); + if (! ok ) + { + nitf_Error_print(&error, stdout, ""); + exit(EXIT_FAILURE); + } + + + printf("\t>Successfully loaded dso!\n"); + + printf("Retrieving [%s]\n", func ); + + if ( nitf_DLL_isValid( dll )) + { + ptr = (void (*)(char**) ) + nitf_DLL_retrieve(dll, func, &error); + /*sleep(20);*/ + if ( ptr == (void (*)(char**))NULL ) + { + printf("Here!!!\n"); + nitf_Error_print(&error, stdout, ""); + exit(EXIT_FAILURE); + } + printf("Calling [%s]\n", func); + + (*ptr)(&argv[1]); + + printf("Argv call [%s]\n", argv[1]); + } + if (!nitf_DLL_unload(dll, &error)) + { + nitf_Error_print(&error, stdout, ""); + } + printf("\t>Successfully unloaded!\n"); + nitf_DLL_destruct(&dll); + + } + fclose( config ); + return 0; +} + diff --git a/modules/c/nitf/tests/test_dll_1.cfg b/modules/c/nitf/tests/test_dll_1.cfg new file mode 100644 index 000000000..85a226924 --- /dev/null +++ b/modules/c/nitf/tests/test_dll_1.cfg @@ -0,0 +1,2 @@ +../plugins/i686-pc-linux-gnu/blah.so blah +../plugins/i686-pc-linux-gnu/writes.so writes diff --git a/modules/c/nitf/tests/test_dump_masks.c b/modules/c/nitf/tests/test_dump_masks.c new file mode 100644 index 000000000..644db3091 --- /dev/null +++ b/modules/c/nitf/tests/test_dump_masks.c @@ -0,0 +1,247 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +/* + Test program to print information relating to block masks + + Call: + + test_dump_masks inputFile + + results go to stdout +*/ + +#include + +NITF_BOOL nitf_ImageIO_getMaskInfo(nitf_ImageIO *nitf, + nitf_Uint32 *imageDataOffset, nitf_Uint32 *blockRecordLength, + nitf_Uint32 *padRecordLength, nitf_Uint32 *padPixelValueLength, + nitf_Uint8 **padValue, nitf_Uint64 **blockMask, nitf_Uint64 **padMask); + +void dumpMask(const char* maskType, + const nitf_Uint64* mask, + size_t numRows, + size_t numCols) +{ + size_t numBlocksPresent = 0; + const size_t numBlocksTotal = numRows * numCols; + size_t row; + size_t col; + size_t idx; + + printf(" %s mask:\n", maskType); + + for (row = 0, idx = 0; row < numRows; ++row) + { + printf(" "); + for (col = 0; col < numCols; ++col, ++idx) + { + if (mask[idx] == 0xFFFFFFFF) + { + printf("_"); + } + else + { + printf("@"); + ++numBlocksPresent; + } + } + printf("\n"); + } + + printf(" %s mask: %zu / %zu blocks (%f%%)\n", + maskType, numBlocksPresent, numBlocksTotal, + numBlocksPresent * 100.0 / numBlocksTotal); +} + +int main(int argc, char *argv[]) +{ + nitf_Reader *reader; /* Reader object */ + nitf_Record *record; /* Record used for input and output */ + nitf_IOHandle in; /* Input I/O handle */ + nitf_ListIterator imgIter; /* Image segment list iterator */ + nitf_ListIterator imgEnd; /* Image segment list iterator */ + nitf_ImageSegment *seg; /* Image segment object */ + nitf_ImageSubheader *subhdr; /* Image subheader object */ + nitf_ImageReader *iReader; /* Image reader */ + nitf_BlockingInfo *blkInfo; /* Blocking information */ + + static nitf_Error errorObj; /* Error object for messages */ + nitf_Error *error; /* Pointer to the error object */ + + /* Image information */ + + char imageMode[NITF_IMODE_SZ+1]; /* Image (blocking) mode */ + + /* Mask structure and mask components */ + + nitf_Uint32 imageDataOffset; /* Offset to actual image data past masks */ + nitf_Uint32 blockRecordLength; /* Block mask record length */ + nitf_Uint32 padRecordLength; /* Pad mask record length */ + nitf_Uint32 padPixelValueLength; /* Pad pixel value length in bytes */ + nitf_Uint8 *padValue; /* Pad value */ + nitf_Uint64 *blockMask; /* Block mask array */ + nitf_Uint64 *padMask; /* Pad mask array */ + size_t imgCtr = 0; + const char* pathname; + + error = &errorObj; + if (argc != 2) + { + fprintf(stderr, "Usage %s inputFile\n", argv[0]); + exit(EXIT_FAILURE); + } + pathname = argv[1]; + + /* Get the input record */ + + in = nitf_IOHandle_create(pathname, + NITF_ACCESS_READONLY, NITF_OPEN_EXISTING, error); + if (NITF_INVALID_HANDLE(in)) + { + nitf_Error_print(error, stderr, "Error opening input "); + exit(EXIT_FAILURE); + } + + reader = nitf_Reader_construct(error); + if (reader == NULL) + { + nitf_IOHandle_close(in); + nitf_Error_print(error, stderr, "Error creating reader "); + exit(EXIT_FAILURE); + } + + record = nitf_Reader_read(reader, in, error); + if (record == NULL) + { + nitf_Reader_destruct(&reader); + nitf_IOHandle_close(in); + nitf_Error_print(error, stderr, "Error reading input "); + exit(EXIT_FAILURE); + } + + /* Loop through the image segments */ + imgIter = nitf_List_begin(record->images); + imgEnd = nitf_List_end(record->images); + + while (nitf_ListIterator_notEqualTo(&imgIter, &imgEnd)) + { + /* Get information from the image subheader */ + seg = (nitf_ImageSegment *) nitf_ListIterator_get(&imgIter); + if (seg == NULL) + { + fprintf(stderr, "No Image segment\n"); + nitf_Reader_destruct(&reader); + nitf_IOHandle_close(in); + exit(EXIT_FAILURE); + } + subhdr = seg->subheader; + + nitf_Field_get(subhdr->imageMode, + imageMode, NITF_CONV_STRING, NITF_IMODE_SZ + 1, error); + imageMode[NITF_IMODE_SZ] = 0; + + /* Get an image reader which creates the nitf_ImageIO were the masks are */ + + iReader = nitf_Reader_newImageReader(reader, imgCtr, NULL, error); + if (iReader == NULL) + { + nitf_Reader_destruct(&reader); + nitf_IOHandle_close(in); + nitf_Record_destruct(&record); + nitf_Error_print(error, stderr, "Error reading input "); + exit(EXIT_FAILURE); + } + + blkInfo = nitf_ImageReader_getBlockingInfo(iReader, error); + if (blkInfo == NULL) + { + nitf_ImageReader_destruct(&iReader); + nitf_Reader_destruct(&reader); + nitf_IOHandle_close(in); + nitf_Record_destruct(&record); + nitf_Error_print(error, stderr, "Error reading input "); + exit(EXIT_FAILURE); + } + + /* Print the blocking information */ + + printf("Image %s segment %zu:\n", pathname, imgCtr); + printf(" Blocking (mode is %s):\n", imageMode); + printf(" Block array dimensions (r,c) = %d %d\n", + blkInfo->numBlocksPerRow, blkInfo->numBlocksPerCol); + printf(" Block dimensions (r,c) = %d,%d\n", + blkInfo->numRowsPerBlock, blkInfo->numColsPerBlock); + printf(" Block length in bytes %zu\n", blkInfo->length); + + /* Get the actual information */ + + if (nitf_ImageIO_getMaskInfo(iReader->imageDeblocker, + &imageDataOffset, &blockRecordLength, + &padRecordLength, &padPixelValueLength, + &padValue, &blockMask, &padMask)) + { + nitf_Uint32 i; + + printf(" Masked image:\n"); + printf(" Image data offset = %d\n", imageDataOffset); + printf(" Block and pad mask record lengths = %u %u\n", + blockRecordLength, padRecordLength); + printf(" Pad value length = %u\n", padPixelValueLength); + printf(" Pad value = "); + for (i = 0;i < padPixelValueLength;i++) + { + printf("%x ", padValue[i]); + } + printf("\n"); + + if (blockRecordLength != 0) + { + dumpMask("Block", + blockMask, + blkInfo->numBlocksPerRow, + blkInfo->numBlocksPerCol); + } + if (padRecordLength != 0) + { + dumpMask("Pad", + padMask, + blkInfo->numBlocksPerRow, + blkInfo->numBlocksPerCol); + } + } + else + { + printf("Not a masked image\n"); + } + + nitf_ImageReader_destruct(&iReader); + nrt_ListIterator_increment(&imgIter); + ++imgCtr; + } + + /* Clean-up */ + nitf_Reader_destruct(&reader); + nitf_IOHandle_close(in); + nitf_Record_destruct(&record); + return(0); +} diff --git a/modules/c/nitf/tests/test_ext.txt b/modules/c/nitf/tests/test_ext.txt new file mode 100644 index 000000000..b80d38cba --- /dev/null +++ b/modules/c/nitf/tests/test_ext.txt @@ -0,0 +1 @@ +DANTRE00011Dan is coolMYSDES00002HiNTFTST00001PDANTRE00005Yes!! diff --git a/modules/c/nitf/tests/test_ext_iter.c b/modules/c/nitf/tests/test_ext_iter.c new file mode 100644 index 000000000..6f93e764b --- /dev/null +++ b/modules/c/nitf/tests/test_ext_iter.c @@ -0,0 +1,244 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + + +#include + + + +#define SHOW(X) printf("%s=[%s]\n", #X, ((X==0)?"(nul)":X)) +#define SHOWI(X) printf("%s=[%ld]\n", #X, X) +#define SHOWLL(X) printf("%s=[%lld]\n", #X, X) +#define SHOWRGB(X) printf("%s(R,G,B)=[%02x,%02x,%02x]\n", #X, (unsigned char) X[0], (unsigned char) X[1], (unsigned char) X[2]) +#define SHOW_VAL(X) printf("%s=[%.*s]\n", #X, ((X==0)?8:((X->raw==0)?5:X->length)), ((X==0)?"(nulptr)":((X->raw==0)?"(nul)":X->raw))) + +void showTRE(nitf_TRE* tre) +{ + nitf_Error error; + if (! nitf_TRE_print(tre, &error)) + nitf_Error_print(&error, stdout, "Ignoring..."); +} + +void showExtSection(nitf_Extensions* ext) +{ + nitf_Error lerror; + if (ext) + { + nitf_ExtensionsIterator extIter; + nitf_ExtensionsIterator endIter; + + if ( nitf_Extensions_exists( ext, "AIMIDB" ) ) + { + printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n"); + printf("DETECTED AIMIDB, REMOVING...\n"); + nitf_Extensions_removeTREsByName(ext, "AIMIDB"); + printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n"); + } + + extIter = nitf_Extensions_begin(ext); + endIter = nitf_Extensions_end(ext); + + while (nitf_ExtensionsIterator_notEqualTo(&extIter, &endIter) ) + { + nitf_TRE* tre = nitf_ExtensionsIterator_get(&extIter); + if ( strcmp( tre->tag, "BLOCKA") == 0 ) + { + printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n"); + printf("DETECTED SINGLE BLOCKA, REMOVING...\n"); + if ( (tre = nitf_Extensions_remove(ext, &extIter, &lerror)) == NULL) + { + nitf_Error_print(&lerror, stdout, "Couldnt blow away blocka!\n"); + } + + printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n"); + printf("NOW RE-INSERTING BLOCK...\n"); + if (! nitf_Extensions_insert(ext, &extIter, tre, &lerror) ) + { + nitf_Error_print(&lerror, stdout, "Couldnt blow away blocka!\n"); + } + printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n"); + + + } + /*printf("TRE: [%s]\n", tre->tag); + showTRE(tre);*/ + nitf_ExtensionsIterator_increment(&extIter); + } + + extIter = nitf_Extensions_begin(ext); + endIter = nitf_Extensions_end(ext); + + while (nitf_ExtensionsIterator_notEqualTo(&extIter, &endIter) ) + { + nitf_TRE* tre = nitf_ExtensionsIterator_get(&extIter); + printf("TRE: [%s]\n", tre->tag); + showTRE(tre); + nitf_ExtensionsIterator_increment(&extIter); + } + + } +} + + + + + +int main(int argc, char **argv) +{ + /* Get the error object */ + nitf_Error error; + + /* This is the reader object */ + nitf_Reader* reader; + nitf_Record* record; + + /* The IO handle */ + nitf_IOHandle io; + int num; + + /* Check argv and make sure we are happy */ + if ( argc != 2 ) + { + printf("Usage: %s \n", argv[0]); + exit(EXIT_FAILURE); + } + + io = nitf_IOHandle_create(argv[1], NITF_ACCESS_READONLY, NITF_OPEN_EXISTING, &error); + if ( NITF_INVALID_HANDLE( io ) ) + { + nitf_Error_print(&error, stdout, "Exiting..."); + exit( EXIT_FAILURE ); + } + + reader = nitf_Reader_construct(&error); + if (!reader) + { + nitf_Error_print(&error, stdout, "Exiting (1) ..."); + exit( EXIT_FAILURE ); + } + + /* record = nitf_Record_construct(&error); + if (!record) + { + nitf_Error_print(&error, stdout, "Exiting (2) ..."); + nitf_Reader_destruct(&reader); + exit( EXIT_FAILURE ); + }*/ + + +#if NITF_VERBOSE_READER + printf("Here are the loaded handlers\n"); + printf("* * * * * * * * * * * * * * * *\n"); + nitf_HashTable_print(reader->reg->treHandlers); + printf("* * * * * * * * * * * * * * * *\n"); +#endif + + if ( ! (record = nitf_Reader_read(reader, io, &error )) ) + { + nitf_Error_print(&error, stdout, "Exiting ..."); + exit(EXIT_FAILURE); + } + + printf("User defined: in file header\n"); + showExtSection(record->header->userDefinedSection); + printf("Extended defined: in file header\n"); + showExtSection(record->header->extendedSection); + + + + if (!nitf_Field_get(record->header->numImages, + &num, + NITF_CONV_INT, + NITF_INT32_SZ, + &error)) + nitf_Error_print(&error, stdout, "Skipping b/c Invalid numImages"); + /* And now show the image information */ + else if (num > 0) + { + + /* Walk each image and show */ + nitf_ListIterator iter = nitf_List_begin(record->images); + nitf_ListIterator end = nitf_List_end(record->images); + + while ( nitf_ListIterator_notEqualTo(&iter, &end) ) + { + nitf_ImageSegment* segment = + (nitf_ImageSegment*)nitf_ListIterator_get(&iter); + + printf("User defined: in image segment\n"); + showExtSection(segment->subheader->userDefinedSection); + printf("Extended defined: in image segment\n"); + showExtSection(segment->subheader->extendedSection); + + + nitf_ListIterator_increment(&iter); + + } + } + else + { + printf("No image in file!\n"); + } + + + + + nitf_IOHandle_close(io); + nitf_Record_destruct(&record); + + if ( !nitf_List_isEmpty(reader->warningList)) + { + /* Iterator to a list */ + nitf_ListIterator it; + + /* Iterator to the end of list */ + nitf_ListIterator endList; + + it = nitf_List_begin(reader->warningList); + + /* End of list pointer */ + endList = nitf_List_end(reader->warningList); + + printf("WARNINGS: "); + printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"); + + /* While we are not at the end */ + while ( nitf_ListIterator_notEqualTo( &it, &endList ) ) + { + /* Get the last data */ + char* p = (char*)nitf_ListIterator_get(&it); + /* Make sure */ + assert(p != NULL); + + /* Show the data */ + printf("\tFound problem: [%s]\n\n", p); + + /* Increment the list iterator */ + nitf_ListIterator_increment(&it); + } + printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"); + } + + nitf_Reader_destruct(&reader); + + return 0; +} diff --git a/modules/c/nitf/tests/test_fhdr_clone.c b/modules/c/nitf/tests/test_fhdr_clone.c new file mode 100644 index 000000000..2af5eb380 --- /dev/null +++ b/modules/c/nitf/tests/test_fhdr_clone.c @@ -0,0 +1,203 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + +#define TRY_IT(X) if (!X) goto CATCH +#define SHOW(X) printf("%s=[%s]\n", #X, X) +#define SHOWI(X) printf("%s=[%ld]\n", #X, X) +#define PRINT_HDR(X) printf("%s:\n", #X); printHdr(X) +#define SHOW_VAL(X) printf("%s=[%.*s]\n", #X, ((X==0)?8:((X->raw==0)?5:(int)X->length)), ((X==0)?"(nulptr)":((X->raw==0)?"(nul)":X->raw))) + +void printHdr(nitf_FileHeader* header) +{ + unsigned int i; + nitf_Uint32 num; + nitf_Error error; + nitf_Uint32 len; + nitf_Uint64 dataLen; + + SHOW_VAL( header->fileHeader ); + SHOW_VAL( header->fileVersion ); + SHOW_VAL( header->complianceLevel ); + SHOW_VAL( header->systemType ); + SHOW_VAL( header->originStationID ); + SHOW_VAL( header->fileDateTime ); + SHOW_VAL( header->fileTitle ); + SHOW_VAL( header->classification ); + SHOW_VAL( header->messageCopyNum ); + SHOW_VAL( header->messageNumCopies ); + SHOW_VAL( header->encrypted ); + SHOW_VAL( header->backgroundColor ); + SHOW_VAL( header->originatorName ); + SHOW_VAL( header->originatorPhone ); + + SHOW_VAL( header->fileLength ); + SHOW_VAL( header->headerLength ); + + /* Attention: If the classification is U, the security group */ + /* section should be empty! For that reason, we wont print */ + /* The security group for now */ + + SHOW_VAL( header->securityGroup->classificationSystem ); + SHOW_VAL( header->securityGroup->codewords ); + SHOW_VAL( header->securityGroup->controlAndHandling ); + SHOW_VAL( header->securityGroup->releasingInstructions ); + SHOW_VAL( header->securityGroup->declassificationType ); + SHOW_VAL( header->securityGroup->declassificationDate ); + SHOW_VAL( header->securityGroup->declassificationExemption ); + SHOW_VAL( header->securityGroup->downgrade ); + SHOW_VAL( header->securityGroup->downgradeDateTime ); + SHOW_VAL( header->securityGroup->classificationText ); + SHOW_VAL( header->securityGroup->classificationAuthorityType ); + SHOW_VAL( header->securityGroup->classificationAuthority ); + SHOW_VAL( header->securityGroup->classificationReason ); + SHOW_VAL( header->securityGroup->securitySourceDate ); + SHOW_VAL( header->securityGroup->securityControlNumber ); + + + NITF_TRY_GET_UINT32(header->numImages, &num, &error); + printf("The number of IMAGES contained in this file [%ld]\n", (long)num); + for (i = 0; i < num; i++) + { + NITF_TRY_GET_UINT32(header->imageInfo[i]->lengthSubheader, &len, &error); + NITF_TRY_GET_UINT64(header->imageInfo[i]->lengthData, &dataLen, &error); + printf("\tThe length of IMAGE subheader [%d]: %ld bytes\n", + i, (long)len); + printf("\tThe length of the IMAGE data: %llu bytes\n\n", + dataLen); + } + + NITF_TRY_GET_UINT32(header->numGraphics, &num, &error); + printf("The number of GRAPHICS contained in this file [%ld]\n", (long)num); + for (i = 0; i < num; i++) + { + NITF_TRY_GET_UINT32(header->graphicInfo[i]->lengthSubheader, &len, &error); + NITF_TRY_GET_UINT64(header->graphicInfo[i]->lengthData, &dataLen, &error); + printf("\tThe length of GRAPHIC subheader [%d]: %ld bytes\n", + i, (long)len); + printf("\tThe length of the GRAPHIC data: %d bytes\n\n", + (int)dataLen); + } + + NITF_TRY_GET_UINT32(header->numLabels, &num, &error); + printf("The number of LABELS contained in this file [%ld]\n", (long)num); + for (i = 0; i < num; i++) + { + NITF_TRY_GET_UINT32(header->labelInfo[i]->lengthSubheader, &len, &error); + NITF_TRY_GET_UINT64(header->labelInfo[i]->lengthData, &dataLen, &error); + printf("\tThe length of LABEL subheader [%d]: %ld bytes\n", + i, (long)len); + printf("\tThe length of the LABEL data: %d bytes\n\n", + (int)dataLen); + } + + NITF_TRY_GET_UINT32(header->numTexts, &num, &error); + printf("The number of TEXTS contained in this file [%ld]\n", (long)num); + for (i = 0; i < num; i++) + { + NITF_TRY_GET_UINT32(header->textInfo[i]->lengthSubheader, &len, &error); + NITF_TRY_GET_UINT64(header->textInfo[i]->lengthData, &dataLen, &error); + printf("\tThe length of TEXT subheader [%d]: %ld bytes\n", + i, (long)len); + printf("\tThe length of the TEXT data: %d bytes\n\n", + (int)dataLen); + } + + NITF_TRY_GET_UINT32(header->numDataExtensions, &num, &error); + printf("The number of DATA EXTENSIONS contained in this file [%ld]\n", (long)num); + for (i = 0; i < num; i++) + { + NITF_TRY_GET_UINT32(header->dataExtensionInfo[i]->lengthSubheader, &len, &error); + NITF_TRY_GET_UINT64(header->dataExtensionInfo[i]->lengthData, &dataLen, &error); + printf("\tThe length of DATA EXTENSION subheader [%d]: %d bytes\n", + i, (int)len); + printf("\tThe length of the DATA EXTENSION data: %d bytes\n\n", + (int)dataLen); + } + + NITF_TRY_GET_UINT32(header->numReservedExtensions, &num, &error); + printf("The number of RESERVED EXTENSIONS contained in this file [%ld]\n", (long)num); + for (i = 0; i < num; i++) + { + NITF_TRY_GET_UINT32(header->reservedExtensionInfo[i]->lengthSubheader, &len, &error); + NITF_TRY_GET_UINT64(header->reservedExtensionInfo[i]->lengthData, &dataLen, &error); + printf("\tThe length of RESERVED EXTENSION subheader [%d]: %d bytes\n", + i, (int)len); + printf("\tThe length of the RESERVED EXTENSION data: %d bytes\n\n", + (int)dataLen); + } + + NITF_TRY_GET_UINT32(header->userDefinedHeaderLength, &num, &error); + printf("The user-defined header length [%ld]\n", (long)num); + + NITF_TRY_GET_UINT32(header->extendedHeaderLength, &num, &error); + printf("The extended header length [%ld]\n", (long)num); + + return; + +CATCH_ERROR: + printf("Error processing\n"); +} + + + +int main(int argc, char** argv) +{ + nitf_IOHandle io; + nitf_Reader* reader; + nitf_Record* record = NULL; + nitf_FileHeader* twin; + nitf_Error error; + + if (argc != 2) + { + printf("Usage: %s \n", argv[0]); + exit(EXIT_FAILURE); + } + + io = nitf_IOHandle_create(argv[1], + NITF_ACCESS_READONLY, + NITF_OPEN_EXISTING, + &error); + TRY_IT( (NITF_INVALID_HANDLE( io )) == 0); + + reader = nitf_Reader_construct(&error); + TRY_IT( reader ); + + + record = nitf_Reader_read(reader, io, &error); + if (!record) + goto CATCH; + + twin = nitf_FileHeader_clone(record->header, &error); + TRY_IT( twin ); + + PRINT_HDR( record->header ); + PRINT_HDR( twin ); + return 0; + +CATCH: + nitf_Error_print(&error, stdout, "main()"); + exit(EXIT_FAILURE); + +} diff --git a/modules/c/nitf/tests/test_field_set.c b/modules/c/nitf/tests/test_field_set.c new file mode 100644 index 000000000..5f88ab011 --- /dev/null +++ b/modules/c/nitf/tests/test_field_set.c @@ -0,0 +1,173 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +/* + Test program for testing field set functions + + This program reads a sets some fields in an image subheader + + +*/ + +#include + +#define STR_LEN 100 /* Test string max length */ + +int main(int argc, char *argv[]) +{ + nitf_FileHeader *fhdr; /* File header supplying fields */ + nitf_ImageSubheader *subhdr; /* Subheader supplying fields */ + nitf_Uint32 valueU32Before; /* Value buffer */ + nitf_Uint32 valueU32After; /* Value buffer */ + nitf_Uint64 valueU64Before; /* Value buffer */ + nitf_Uint64 valueU64After; /* Value buffer */ + char *valueStrBefore; /* Value buffer */ + /* Value buffer */ + static char valueStrAfter[STR_LEN + 2]; + nitf_Uint32 valueStrLen; /* Value buffer */ + static nitf_Error errorObj; /* Error object for messages */ + nitf_Error *error; /* Pointer to the error object */ + + error = &errorObj; + + fhdr = nitf_FileHeader_construct(error); + if (fhdr == NULL) + { + nitf_Error_print(error, stdout, "Error creating image subheader"); + exit(EXIT_FAILURE); + } + + subhdr = nitf_ImageSubheader_construct(error); + if (subhdr == NULL) + { + nitf_Error_print(error, stdout, "Error creating image subheader"); + exit(EXIT_FAILURE); + } + + /* Set some fields (should work) */ + valueU32Before = 12345; + if (nitf_Field_setUint32(subhdr->NITF_XBANDS, valueU32Before, error)) + fprintf(stdout, + "Set of XBANDS via nitf_Field_setUint32 worked as expected\n"); + else + nitf_Error_print(error, stdout, + "Unexpected error setting XBANDS via nitf_Field_setUint32"); + + nitf_Field_get(subhdr->NITF_XBANDS, (NITF_DATA *) & valueU32After, + NITF_CONV_UINT, NITF_INT32_SZ, error); + fprintf(stdout, + "Set of XBANDS via nitf_Field_setUint32 original %d readback %d\n", + valueU32Before, valueU32After); + + valueU32Before = 1234; + if (nitf_Field_setUint32(subhdr->NITF_COMRAT, valueU32Before, error)) + fprintf(stdout, + "Set of COMRAT via nitf_Field_setUint32 worked as expected\n"); + else + nitf_Error_print(error, stdout, + "Unexpected error setting COMRAT via nitf_Field_setUint32"); + + nitf_Field_get(subhdr->NITF_COMRAT, (NITF_DATA *) & valueU32After, + NITF_CONV_UINT, NITF_INT32_SZ, error); + fprintf(stdout, + "Set of COMRAT via nitf_Field_setUint32 original %d readback %d\n", + valueU32Before, valueU32After); + + valueU64Before = 11234567890ll; + if (nitf_Field_setUint64(fhdr->NITF_FL, valueU64Before, error)) + fprintf(stdout, + "Set of FL via nitf_Field_setUint64 worked as expected\n"); + else + nitf_Error_print(error, stdout, + "Unexpected error setting FL via nitf_Field_setUint64"); + + nitf_Field_get(fhdr->NITF_FL, (NITF_DATA *) & valueU64After, + NITF_CONV_UINT, NITF_INT64_SZ, error); + fprintf(stdout, + "Set of FL via nitf_Field_setUint64 original %llu readback %llu\n", + valueU64Before, valueU64After); + + valueStrBefore = "TestStr"; + if (nitf_Field_setString(subhdr->NITF_IID2, valueStrBefore, error)) + fprintf(stdout, + "Set of IID2 via nitf_Field_setString worked as expected\n"); + else + nitf_Error_print(error, stdout, + "Unexpected error setting IID2 via nitf_Field_setString"); + + nitf_Field_get(subhdr->NITF_IID2, (NITF_DATA *) valueStrAfter, + NITF_CONV_STRING, STR_LEN, error); + fprintf(stdout, + "Set of IID2 via nitf_Field_setString original %s readback %s\n", + valueStrBefore, valueStrAfter); + + valueStrBefore = "1234"; + if (nitf_Field_setString(subhdr->NITF_NCOLS, valueStrBefore, error)) + fprintf(stdout, + "Set of NCOLS via nitf_Field_setString worked as expected\n"); + else + nitf_Error_print(error, stdout, + "Unexpected error setting NCOLS via nitf_Field_setString"); + + nitf_Field_get(subhdr->NITF_NCOLS, (NITF_DATA *) valueStrAfter, + NITF_CONV_STRING, STR_LEN, error); + fprintf(stdout, + "Set of NCOLS via nitf_Field_setString original %s readback %s\n", + valueStrBefore, valueStrAfter); + + /* Set some fields (should fail) */ + + valueU32Before = 123; + if (nitf_Field_setUint32(fhdr->NITF_FBKGC, valueU32Before, error)) + fprintf(stdout, + "Set of FBKGC via nitf_Field_setUnit32 worked expected error\n"); + else + nitf_Error_print(error, stdout, + "Expected error setting FBKGC via nitf_Field_setUint32"); + + valueStrBefore = "123"; + if (nitf_Field_setString(fhdr->NITF_FBKGC, valueStrBefore, error)) + fprintf(stdout, + "Set of FBKGC via nitf_Field_setString worked expected error\n"); + else + nitf_Error_print(error, stdout, + "Expected error setting FBKGC via nitf_Field_setString"); + + valueStrBefore = "12g"; + if (nitf_Field_setString(subhdr->NITF_NCOLS, valueStrBefore, error)) + fprintf(stdout, + "Set of NCOLS via nitf_Field_setString worked expected error\n"); + else + nitf_Error_print(error, stdout, + "Expected error setting NCOLS via nitf_Field_setString"); + + valueU32Before = 3; + if (nitf_Field_setUint32(subhdr->NITF_NBANDS, valueU32Before, error)) + fprintf(stdout, + "Set of NBANDS via nitf_Field_setUint32 worked expected error\n"); + else + nitf_Error_print(error, stdout, + "Expected error setting NBANDS via nitf_Field_setUint32"); + + return 0; + +} diff --git a/modules/c/nitf/tests/test_fileIO.c b/modules/c/nitf/tests/test_fileIO.c new file mode 100644 index 000000000..e347250b0 --- /dev/null +++ b/modules/c/nitf/tests/test_fileIO.c @@ -0,0 +1,763 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +/******************************************************************************* +** status = test_large_fileIO(fullFileName) +** +**PURPOSE: +** This function tests the file IO functions. It is intended to reveal +** problems related to 32 vs 64 bit referencing (i.e. try files > 4GB). +** +**INPUT ARGUMENTS: +** fullFileName - A C style string indicating the file to test on +** +**RETURN VALUES: +** status - An integer indicating the return status. 1 if successful +** and 0 otherwise +** +*******************************************************************************/ +#include +#include + +/******************************************************************************* +*************************** Function Prototypes **************************** +*******************************************************************************/ + +/******************************************************************************** +**PURPOSE: +** This function parses the input arguments and checks them for errors. If an +** error occures 0 is returned and a nitf_Error object is populated. +** +**INPUT ARGUMENTS: +** argc - Number of input arguments +** argv - Pointer to an array ofinput parameters +** errorPtr - Pointer to a nitf error object +** fullFileName - Pointer to a pointer to the fullFileName (test file) +** +**RETURN VALUES: +** status - An integer indicating the return status. 1 if successful +** and 0 otherwise +** +*******************************************************************************/ +int parseInputs(int argc, char** argv, nitf_Error* errorPtr, char** fullFileName); + + +/******************************************************************************** +**PURPOSE: +** This function tests the IO create and close methods. +** +**INPUT ARGUMENTS: +** fullFileName - Pointer to a c-style string describing the fully +** qualified filename +** scratchFullFileName - Pointer to a c-style string describing the fully +** qualified filename of the scratch file +** errorPtr - Pointer to a nitf error object +** +**RETURN VALUES: +** status - An integer indicating the return status. 1 if successful +** and 0 otherwise +** +*******************************************************************************/ +int checkCreateClose(char* fullFileName, char* scratchFullFileName, nitf_Error* errorPtr); + + +/******************************************************************************** +**PURPOSE: +** This function tests the getSize method +** +**INPUT ARGUMENTS: +** fullFileName - Pointer to a c-style string describing the fully +** qualified filename +** scratchFullFileName - Pointer to a c-style string describing the fully +** qualified filename of the scratch file +** errorPtr - Pointer to a nitf error object +** +**RETURN VALUES: +** fileSize - An nitf_Off indicating the file size or -1 on failure +** +*******************************************************************************/ +nitf_Off checkGetSize(char* fullFileName, char* scratchFullFileName, nitf_Error* errorPtr); + + +/******************************************************************************** +**PURPOSE: +** This function tests the seek/tell methods +** +**INPUT ARGUMENTS: +** fullFileName - Pointer to a c-style string describing the fully +** qualified filename +** fileSize - Size of the input file in bytes +** errorPtr - Pointer to a nitf error object +** +**RETURN VALUES: +** status - An integer indicating the return status. 1 if successful +** and 0 otherwise +** +*******************************************************************************/ +int checkSeekTell(char* fullFileName, nitf_Off fileSize, nitf_Error* errorPtr); +int checkSeekTell_test(nitf_IOHandle ioHandle, nitf_Off fileSize, nitf_Error* errorPtr); + + +/******************************************************************************** +**PURPOSE: +** This function tests the read/write methods +** +**INPUT ARGUMENTS: +** fullFileName - Pointer to a c-style string describing the fully +** qualified filename +** fileSize - Size of the input file in bytes +** errorPtr - Pointer to a nitf error object +** +**RETURN VALUES: +** status - 1 if successful and 0 otherwise +** +*******************************************************************************/ +int checkReadWrite(char* fullFileName, nitf_Off fileSize, nitf_Error* errorPtr); + + +/******************************************************************************* +************************************ Main ********************************** +*******************************************************************************/ +int main(int argc, char** argv) +{ + /**************************** + *** Variable Declarations *** + ****************************/ + nitf_Error error; /* Error object */ + nitf_Off fileSize; /* size in bytes of the test file */ + char* fullFileName; /* C style string containing the test file*/ + char scratchFullFileName[1024]; /* C style string for a scratch file to be created */ + + + /********************************* + *** Parse the input parameters *** + *********************************/ + if ( !parseInputs(argc, argv, &error, &fullFileName) ) + { + printf("Error Parsing Input Parameters: %s\n", error.message); + exit( EXIT_FAILURE ); + } + + + /********************************************** + *** Get a filename to use as a scratch file *** + **********************************************/ + strcpy(scratchFullFileName, fullFileName); + strcat(scratchFullFileName, "_temporary_IOTest_scratch"); + + + /**************************** + *** Display size of nitf_Off *** + ****************************/ + printf("Size of nitf_Off: %i bits \n", (int)sizeof(nitf_Off)*8 ); + + + /******************************** + *** Test create/close methods *** + ********************************/ + printf("\nTesting create/close methods... \n"); + if ( !checkCreateClose(fullFileName, scratchFullFileName, &error) ) + { + printf("Error in create/close methods: Further testing has been skipped"); + exit( EXIT_FAILURE ); + } + + + /***************************** + *** Test getSize operation *** + *****************************/ + printf("\nTesting getSize method... \n"); + fileSize = checkGetSize(fullFileName, scratchFullFileName, &error); + if ( fileSize == -1) + { + printf("Error in getSize method: Further testing has been skipped"); + exit( EXIT_FAILURE ); + } + + + /******************************** + *** Test seek/tell operations *** + ********************************/ + printf("\nTesting seek/tell methods... \n"); + if ( !checkSeekTell(fullFileName, fileSize, &error) ) + { + printf("Error in seek/tell methods: Further testing has been skipped"); + exit( EXIT_FAILURE ); + } + + + /********************************* + *** Test read/write operations *** + *********************************/ + printf("\nTesting read/write methods... \n"); + if ( !checkReadWrite(fullFileName, fileSize, &error) ) + { + printf("Error in read/write methods: Further testing has been skipped"); + exit( EXIT_FAILURE ); + } + + printf("\nAll tests passed. \n\nDon't forget to delete the scratch file: \n%s", scratchFullFileName); + return( EXIT_SUCCESS ); +} + + +/******************************************************************************* +******************************************************************************** +************************** Function Declarations *************************** +******************************************************************************** +*******************************************************************************/ + + +int parseInputs(int argc, char** argv, nitf_Error* errorPtr, char** fullFileName) +{ + /* Check the number of input arg */ + if ( argc != 2 ) + { + nitf_Error_init(errorPtr, "Invalid number of input arguments", NITF_CTXT, NITF_ERR_INVALID_PARAMETER); + return( 0 ); + } + + /* Assume that the file name is correct (This will be tested during the open) */ + *fullFileName = argv[1]; + + return( 1 ); +} + + +int checkCreateClose(char* fullFileName, char* scratchFullFileName, nitf_Error* errorPtr) +{ + /**************************** + *** Variable Declarations *** + ****************************/ + nitf_IOHandle ioHandle; /* IO handle */ + + + /********************* + *** Test read-only *** + *********************/ + ioHandle = nitf_IOHandle_create(fullFileName, + NITF_OPEN_EXISTING, + NITF_ACCESS_READONLY, + errorPtr); + if ( NITF_IO_SUCCESS(ioHandle) ) + { + nitf_IOHandle_close(ioHandle); + printf("Read-Only Passed \n"); + } + else + { + nitf_Error_print(errorPtr, stdout, "Unable create read-only ioHandle \n"); + return( 0 ); + } + + + /********************** + *** Test write-only *** + **********************/ + ioHandle = nitf_IOHandle_create(fullFileName, + NITF_OPEN_EXISTING, + NITF_ACCESS_WRITEONLY, errorPtr); + if ( NITF_IO_SUCCESS(ioHandle) ) + { + nitf_IOHandle_close(ioHandle); + printf("Write-Only Passed \n"); + } + else + { + nitf_Error_print(errorPtr, stdout, "Unable create write-only ioHandle \n"); + return( 0 ); + } + + + /********************** + *** Test read/write *** + **********************/ + ioHandle = nitf_IOHandle_create(fullFileName, + NITF_OPEN_EXISTING, + NITF_READWRITE, errorPtr); + if ( NITF_IO_SUCCESS(ioHandle) ) + { + nitf_IOHandle_close(ioHandle); + printf("Read-Write Passed \n"); + } + else + { + nitf_Error_print(errorPtr, stdout, "Unable create read-write ioHandle \n"); + return( 0 ); + } + + + /****************** + *** Test create *** + ******************/ + /* Test the creation of a new file */ + ioHandle = nitf_IOHandle_create(scratchFullFileName, + NITF_CREATE, + NITF_ACCESS_READONLY, + errorPtr); + if ( NITF_IO_SUCCESS(ioHandle) ) + { + nitf_IOHandle_close(ioHandle); + } + else + { + nitf_Error_print(errorPtr, stdout, "Unable create create ioHandle \n"); + return( 0 ); + } + + /* Test the overwriting of a file */ + ioHandle = nitf_IOHandle_create(scratchFullFileName, + NITF_CREATE, + NITF_ACCESS_READONLY, errorPtr); + if ( NITF_IO_SUCCESS(ioHandle) ) + { + nitf_IOHandle_close(ioHandle); + printf("Create Passed \n"); + } + else + { + nitf_Error_print(errorPtr, stdout, "Unable create create ioHandle \n"); + return( 0 ); + } + + return( 1 ); +} + + +nitf_Off checkGetSize(char* fullFileName, char* scratchFullFileName, nitf_Error* errorPtr) +{ + /**************************** + *** Variable Declarations *** + ****************************/ + nitf_IOHandle ioHandle; /* IO handle */ + nitf_Off fileSize; + nitf_Off tempFileSize; + + + /*********** + *** Test *** + ***********/ + + /* Open the file read-only */ + ioHandle = nitf_IOHandle_create(fullFileName, + NITF_OPEN_EXISTING, + NITF_ACCESS_READONLY, errorPtr); + if ( !NITF_IO_SUCCESS(ioHandle) ) + { + nitf_Error_print(errorPtr, stdout, "Unable create read-only ioHandle \n"); + return( -1 ); + } + + /* Get the fileSize */ + fileSize = nitf_IOHandle_getSize(ioHandle, errorPtr); + + /* Close the ioHandle */ + nitf_IOHandle_close(ioHandle); + + /* Check the fileSize */ + if ( fileSize < 0 ) + { + nitf_Error_print(errorPtr, stdout, "Unable get fileSize \n"); + return( -1 ); + } + + + /* Open the file write-only */ + ioHandle = nitf_IOHandle_create(fullFileName, + NITF_OPEN_EXISTING, + NITF_WRITEONLY, errorPtr); + if ( !NITF_IO_SUCCESS(ioHandle) ) + { + nitf_Error_print(errorPtr, stdout, "Unable create write-only ioHandle \n"); + return( -1 ); + } + + /* Get the fileSize */ + tempFileSize = nitf_IOHandle_getSize(ioHandle, errorPtr); + + /* Close the ioHandle */ + nitf_IOHandle_close(ioHandle); + + /* Check the fileSize */ + if (tempFileSize != fileSize ) + { + nitf_Error_print(errorPtr, stdout, "Unable get fileSize \n"); + return( -1 ); + } + + + /* Open the file read-write */ + ioHandle = nitf_IOHandle_create(fullFileName, NITF_READWRITE, errorPtr); + if ( !NITF_IO_SUCCESS(ioHandle) ) + { + nitf_Error_print(errorPtr, stdout, "Unable create write-only ioHandle \n"); + return( -1 ); + } + + /* Get the fileSize */ + tempFileSize = nitf_IOHandle_getSize(ioHandle, errorPtr); + + /* Close the ioHandle */ + nitf_IOHandle_close(ioHandle); + + /* Check the fileSize */ + if (tempFileSize != fileSize ) + { + nitf_Error_print(errorPtr, stdout, "Unable get fileSize \n"); + return( -1 ); + } + + + /* Open the file with create */ + ioHandle = nitf_IOHandle_create(scratchFullFileName, + NITF_ACCESS_READONLY, + NITF_CREATE, errorPtr); + if ( !NITF_IO_SUCCESS(ioHandle) ) + { + nitf_Error_print(errorPtr, stdout, "Unable create create ioHandle \n"); + return( -1 ); + } + + /* Get the fileSize */ + tempFileSize = nitf_IOHandle_getSize(ioHandle, errorPtr); + + /* Close the ioHandle */ + nitf_IOHandle_close(ioHandle); + + /* Check the fileSize */ + if (tempFileSize < 0 ) + { + nitf_Error_print(errorPtr, stdout, "Unable get fileSize \n"); + return( -1 ); + } + + printf("Passed: File Size = %.0lf \n", (double)fileSize ); + return( fileSize ); +} + + +int checkSeekTell(char* fullFileName, nitf_Off fileSize, nitf_Error* errorPtr) +{ + /**************************** + *** Variable Declarations *** + ****************************/ + nitf_IOHandle ioHandle; /* IO handle */ + int passFlag; + + + /********************* + *** Test read-only *** + *********************/ + + ioHandle = nitf_IOHandle_create(fullFileName, + NITF_OPEN_EXISTING, + NITF_ACCESS_READONLY, errorPtr); + if ( !NITF_IO_SUCCESS(ioHandle) ) + { + nitf_Error_print(errorPtr, stdout, "Unable create read-only ioHandle \n"); + return( 0 ); + } + + passFlag = checkSeekTell_test(ioHandle, fileSize, errorPtr); + nitf_IOHandle_close(ioHandle); + + if ( !passFlag ) + { + return( 0 ); + } + + + /********************** + *** Test write-only *** + **********************/ + ioHandle = nitf_IOHandle_create(fullFileName, + NITF_OPEN_EXISTING, + NITF_WRITEONLY, errorPtr); + if ( !NITF_IO_SUCCESS(ioHandle) ) + { + nitf_Error_print(errorPtr, stdout, "Unable create read-only ioHandle \n"); + return( 0 ); + } + + passFlag = checkSeekTell_test(ioHandle, fileSize, errorPtr); + nitf_IOHandle_close(ioHandle); + + if ( !passFlag ) + { + return( 0 ); + } + + + /********************** + *** Test read-write *** + **********************/ + ioHandle = nitf_IOHandle_create(fullFileName, + NITF_OPEN_EXISTING, + NITF_ACCESS_READWRITE, errorPtr); + if ( !NITF_IO_SUCCESS(ioHandle) ) + { + nitf_Error_print(errorPtr, stdout, "Unable create read-only ioHandle \n"); + return( 0 ); + } + + passFlag = checkSeekTell_test(ioHandle, fileSize, errorPtr); + nitf_IOHandle_close(ioHandle); + + if ( !passFlag ) + { + return( 0 ); + } + + + printf("Passed \n"); + return( 1 ); +} + + +int checkSeekTell_test(nitf_IOHandle ioHandle, nitf_Off fileSize, nitf_Error* errorPtr) +{ + + /* From start of file */ + if ( !NITF_IO_SUCCESS( nitf_IOHandle_seek(ioHandle, 0, NITF_SEEK_SET, errorPtr) ) ) + { + nitf_Error_print(errorPtr, stdout, "Unable to seek in file \n"); + return( 0 ); + } + if ( nitf_IOHandle_tell(ioHandle, errorPtr) != 0 ) + { + nitf_Error_print(errorPtr, stdout, "Unable to query file position \n"); + return( 0 ); + } + if ( !NITF_IO_SUCCESS( nitf_IOHandle_seek(ioHandle, fileSize, NITF_SEEK_SET, errorPtr) ) ) + { + nitf_Error_print(errorPtr, stdout, "Unable to seek in file \n"); + return( 0 ); + } + if ( nitf_IOHandle_tell(ioHandle, errorPtr) != fileSize ) + { + nitf_Error_print(errorPtr, stdout, "Unable to query file position \n"); + return( 0 ); + } + if ( !NITF_IO_SUCCESS( nitf_IOHandle_seek(ioHandle, 0, NITF_SEEK_SET, errorPtr) ) ) + { + nitf_Error_print(errorPtr, stdout, "Unable to seek in file \n"); + return( 0 ); + } + if ( nitf_IOHandle_tell(ioHandle, errorPtr) != 0 ) + { + nitf_Error_print(errorPtr, stdout, "Unable to query file position \n"); + return( 0 ); + } + + /* From current position */ + if ( !NITF_IO_SUCCESS( nitf_IOHandle_seek(ioHandle, 0, NITF_SEEK_CUR, errorPtr) ) ) + { + nitf_Error_print(errorPtr, stdout, "Unable to seek in file \n"); + return( 0 ); + } + if ( nitf_IOHandle_tell(ioHandle, errorPtr) != 0 ) + { + nitf_Error_print(errorPtr, stdout, "Unable to query file position \n"); + return( 0 ); + } + if ( !NITF_IO_SUCCESS( nitf_IOHandle_seek(ioHandle, fileSize, NITF_SEEK_CUR, errorPtr) ) ) + { + nitf_Error_print(errorPtr, stdout, "Unable to seek in file \n"); + return( 0 ); + } + if ( nitf_IOHandle_tell(ioHandle, errorPtr) != fileSize ) + { + nitf_Error_print(errorPtr, stdout, "Unable to query file position \n"); + return( 0 ); + } + if ( !NITF_IO_SUCCESS( nitf_IOHandle_seek(ioHandle, -fileSize, NITF_SEEK_CUR, errorPtr) ) ) + { + nitf_Error_print(errorPtr, stdout, "Unable to seek in file \n"); + return( 0 ); + } + if ( nitf_IOHandle_tell(ioHandle, errorPtr) != 0 ) + { + nitf_Error_print(errorPtr, stdout, "Unable to query file position \n"); + return( 0 ); + } + + /* From end of file */ + if ( !NITF_IO_SUCCESS( nitf_IOHandle_seek(ioHandle, -fileSize, NITF_SEEK_END, errorPtr) ) ) + { + nitf_Error_print(errorPtr, stdout, "Unable to seek in file \n"); + return( 0 ); + } + if ( nitf_IOHandle_tell(ioHandle, errorPtr) != 0 ) + { + nitf_Error_print(errorPtr, stdout, "Unable to query file position \n"); + return( 0 ); + } + if ( !NITF_IO_SUCCESS( nitf_IOHandle_seek(ioHandle, 0, NITF_SEEK_END, errorPtr) ) ) + { + nitf_Error_print(errorPtr, stdout, "Unable to seek in file \n"); + return( 0 ); + } + if ( nitf_IOHandle_tell(ioHandle, errorPtr) != fileSize ) + { + nitf_Error_print(errorPtr, stdout, "Unable to query file position \n"); + return( 0 ); + } + if ( !NITF_IO_SUCCESS( nitf_IOHandle_seek(ioHandle, -fileSize, NITF_SEEK_END, errorPtr) ) ) + { + nitf_Error_print(errorPtr, stdout, "Unable to seek in file \n"); + return( 0 ); + } + if ( nitf_IOHandle_tell(ioHandle, errorPtr) != 0 ) + { + nitf_Error_print(errorPtr, stdout, "Unable to query file position \n"); + return( 0 ); + } + + return( 1 ); +} + + +int checkReadWrite(char* fullFileName, nitf_Off fileSize, nitf_Error* errorPtr) +{ + /**************************** + *** Variable Declarations *** + ****************************/ +#define READ_BUFFER_SIZE 16777216 + int result; /* return status */ + nitf_IOHandle ioHandle; /* IO handle */ + char* readBuffer; + int longReadSize; /* Number of bytes in a "long" read */ + nitf_Off longOffset; /* Offset to test the 32 bit limit if possible */ + + + /******************************* + *** Allocate the read buffer *** + *******************************/ + readBuffer = NITF_MALLOC(sizeof(char) * READ_BUFFER_SIZE); + if (readBuffer == NULL) + { + printf("UNABLE TO ALLOCATE DYNAMIC MEMORY!"); + exit(0); + } + + + /*********************************************** + *** Open the file with read-write permission *** + ***********************************************/ + ioHandle = nitf_IOHandle_create(fullFileName, NITF_READWRITE, errorPtr); + if ( !NITF_IO_SUCCESS(ioHandle) ) + { + nitf_Error_print(errorPtr, stdout, "Unable create read-write ioHandle \n"); + goto ERROR; + } + + + /******************************* + *** Determine long read size *** + *******************************/ + if ( fileSize >= READ_BUFFER_SIZE ) + longReadSize = READ_BUFFER_SIZE; + else + longReadSize = fileSize; + + + /******************* + *** Test Reading *** + *******************/ + + /* Read 1 byte from the beginning of the file */ + if ( !NITF_IO_SUCCESS( nitf_IOHandle_read(ioHandle, readBuffer, 1, errorPtr) ) ) + { + nitf_Error_print(errorPtr, stdout, "Unable to read from file \n"); + goto ERROR; + } + + /* Seek back to the beginning */ + if ( !NITF_IO_SUCCESS( nitf_IOHandle_seek(ioHandle, 0, NITF_SEEK_SET, errorPtr) ) ) + { + nitf_Error_print(errorPtr, stdout, "Unable to seek in file \n"); + goto ERROR; + } + + /* Make a long read from the beginning of the file */ + if ( !NITF_IO_SUCCESS( nitf_IOHandle_read(ioHandle, readBuffer, longReadSize, errorPtr) ) ) + { + nitf_Error_print(errorPtr, stdout, "Unable to read from file \n"); + goto ERROR; + } + + /* Look for the 32 bit limit or the end of the file */ + if (fileSize > 2147483648) /* NOTE: There is typically a sign bit */ + longOffset = 2147483648 - longReadSize + 1; + else + longOffset = fileSize - longReadSize; + + /* Seek to longOffset */ + if ( !NITF_IO_SUCCESS( nitf_IOHandle_seek(ioHandle, longOffset, NITF_SEEK_SET, errorPtr) ) ) + { + nitf_Error_print(errorPtr, stdout, "Unable to seek in file \n"); + goto ERROR; + } + + /* Make a read across the 32 bit limit if possible */ + if ( !NITF_IO_SUCCESS( nitf_IOHandle_read(ioHandle, readBuffer, longReadSize, errorPtr) ) ) + { + nitf_Error_print(errorPtr, stdout, "Unable to read from file \n"); + goto ERROR; + } + + /* Seek to the end of the file minus 1 byte */ + if ( !NITF_IO_SUCCESS( nitf_IOHandle_seek(ioHandle, -1, NITF_SEEK_END, errorPtr) ) ) + { + nitf_Error_print(errorPtr, stdout, "Unable to seek in file \n"); + goto ERROR; + } + + /* Read 1 byte from the end of the file */ + if ( !NITF_IO_SUCCESS( nitf_IOHandle_read(ioHandle, readBuffer, 1, errorPtr) ) ) + { + nitf_Error_print(errorPtr, stdout, "Unable to read from file \n"); + goto ERROR; + } + + /* We Succeeded! */ + goto SUCCESS; + + /* Handle Any Errors */ +ERROR: + + nitf_IOHandle_close(ioHandle); + result = 0; + goto EXIT; + + /* Handle Success */ +SUCCESS: + + nitf_IOHandle_close(ioHandle); + result = 1; + printf("Passed \n"); + goto EXIT; + +EXIT: + NITF_FREE(readBuffer); + return( result ); +} diff --git a/modules/c/nitf/tests/test_file_source.c b/modules/c/nitf/tests/test_file_source.c new file mode 100644 index 000000000..7455b804c --- /dev/null +++ b/modules/c/nitf/tests/test_file_source.c @@ -0,0 +1,141 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + +#define MEMBUF "A1B2C3A1B2C3A1B2C3A1B2C3A1B2C3A1B2C3A1B2C3" +#define MEMSIZE strlen(MEMBUF) +#define NUM_BANDS 3 +#define NUM_BYTES_PER_BAND 2 +#define FILENM "test_file.src" +void print_band(char *band, const char *s, int size) +{ + int i; + printf("Band %s: [", s); + for (i = 0; i < size; i++) + { + printf("%c", band[i]); + } + printf("]\n"); +} + +nitf_IOHandle prepare_io() +{ + /* First we'll create the file for them... */ + nitf_Error error; + nitf_IOHandle handle = + nitf_IOHandle_create(FILENM, NITF_ACCESS_WRITEONLY, NITF_CREATE, + &error); + if (NITF_INVALID_HANDLE(handle)) + { + nitf_Error_print(&error, stdout, "Quitting!"); + exit(EXIT_FAILURE); + } + /* And we'll write our buffer out */ + nitf_IOHandle_write(handle, MEMBUF, MEMSIZE, &error); + nitf_IOHandle_close(handle); + + + /* Now we'll reopen in readonly fashion */ + handle = nitf_IOHandle_create(FILENM, NITF_ACCESS_READONLY, + NITF_CREATE, &error); + if (NITF_INVALID_HANDLE(handle)) + { + nitf_Error_print(&error, stdout, "Quitting!"); + exit(EXIT_FAILURE); + } + return handle; +} + +int main(int argc, char **argv) +{ + /* Get the error object */ + nitf_Error error; + int bandSize = MEMSIZE / NUM_BANDS; + nitf_IOHandle handle = prepare_io(); + + int numBytesPerPix = 1; + + + /* Construct the band sources */ + nitf_BandSource *bs0 = + nitf_FileSource_construct(handle, 0, numBytesPerPix, + NUM_BANDS - 1, &error); + nitf_BandSource *bs1 = + nitf_FileSource_construct(handle, 1, numBytesPerPix, + NUM_BANDS - 1, &error); + nitf_BandSource *bs2 = + nitf_FileSource_construct(handle, 2, numBytesPerPix, + NUM_BANDS - 1, &error); + nitf_BandSource *all = nitf_FileSource_construct(handle, 0, + /* gets ignored */ + numBytesPerPix, + 0, &error); + + /* Construct in memory band buffers -- for testing -- 0 terminate strings */ + char *band_0 = (char *) NITF_MALLOC(bandSize + 1); + char *band_1 = (char *) NITF_MALLOC(bandSize + 1); + char *band_2 = (char *) NITF_MALLOC(bandSize + 1); + char *all_bands = (char *) NITF_MALLOC(MEMSIZE + 1); + + band_0[bandSize] = 0; + band_1[bandSize] = 1; + band_2[bandSize] = 2; + all_bands[MEMSIZE] = 0; + assert(nitf_IOHandle_getSize(handle, &error) == MEMSIZE); + + /* Read half of the info for one band. This makes sure that we */ + /* are capable of picking up where we left off */ + bs0->iface->read(bs0->data, band_0, (MEMSIZE / NUM_BANDS / 2), &error); + bs1->iface->read(bs1->data, band_1, (MEMSIZE / NUM_BANDS / 2), &error); + bs2->iface->read(bs2->data, band_2, (MEMSIZE / NUM_BANDS / 2), &error); + + /* Pick up where we left off and keep going */ + bs0->iface->read(bs0->data, &band_0[MEMSIZE / NUM_BANDS / 2], + (MEMSIZE / NUM_BANDS / 2), &error); + bs1->iface->read(bs1->data, &band_1[MEMSIZE / NUM_BANDS / 2], + (MEMSIZE / NUM_BANDS / 2), &error); + bs2->iface->read(bs2->data, &band_2[MEMSIZE / NUM_BANDS / 2], + (MEMSIZE / NUM_BANDS / 2), &error); + all->iface->read(all->data, all_bands, MEMSIZE, &error); + + /* Now we would like to verify the results of our reading */ + + /* The first three bands should be all of the same letter B1=A, B2=B, B3=C */ + print_band(band_0, "1", MEMSIZE / NUM_BANDS); + print_band(band_1, "2", MEMSIZE / NUM_BANDS); + print_band(band_2, "3", MEMSIZE / NUM_BANDS); + + /* The last band source was applied to the entire buffer, so it should */ + /* look the same as the original memory source */ + print_band(all_bands, "ALL", MEMSIZE); + + NITF_FREE(band_0); + NITF_FREE(band_1); + NITF_FREE(band_2); + NITF_FREE(all_bands); + nitf_BandSource_destruct(&bs0); + nitf_BandSource_destruct(&bs1); + nitf_BandSource_destruct(&bs2); + nitf_BandSource_destruct(&all); + return 0; +} diff --git a/modules/c/nitf/tests/test_find_field.c b/modules/c/nitf/tests/test_find_field.c new file mode 100644 index 000000000..2b3c02443 --- /dev/null +++ b/modules/c/nitf/tests/test_find_field.c @@ -0,0 +1,167 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + +void lookForTREField(nitf_Extensions* ext, + const char* tag, + const char* pattern) +{ + nitf_ListIterator current, last; + + nitf_List* list = nitf_Extensions_getTREsByName(ext, tag); + if (list == NULL) return; + + current = nitf_List_begin(list); + last = nitf_List_end(list); + + while (nitf_ListIterator_notEqualTo(¤t, &last)) + { + nitf_Error error; + nitf_TRE* tre = nitf_ListIterator_get(¤t); + nitf_ListIterator currentInst; + nitf_ListIterator lastInst; + + nitf_List* found = nitf_TRE_find(tre, pattern, &error); + if (!found) return; + + + currentInst = nitf_List_begin(found); + lastInst = nitf_List_end(found); + + while (nitf_ListIterator_notEqualTo(¤tInst, &lastInst)) + { + nitf_Pair* pair = nitf_ListIterator_get(¤tInst); + nitf_Field* field = (nitf_Field*)pair->data; + printf("Found: %s [%.*s]\n", pair->key, (int)field->length, field->raw); + nitf_ListIterator_increment(¤tInst); + + } + nitf_ListIterator_increment(¤t); + } + + +} + +int main(int argc, char **argv) +{ + /* Get the error object */ + nitf_Error error; + + /* so I can remember what Im doing with args */ + const char* treName; + const char* fieldName; + + /* This is the reader object */ + nitf_Reader *reader; + nitf_Record *record; + + /* The IO handle */ + nitf_IOHandle io; + int num; + + /* Check argv and make sure we are happy */ + if (argc != 4) + { + printf("Usage: %s \n", argv[0]); + exit(EXIT_FAILURE); + } + + if (nitf_Reader_getNITFVersion(argv[1]) == NITF_VER_UNKNOWN) + { + printf("File: %s is not a NITF\n", argv[1]); + exit(EXIT_FAILURE); + } + + treName = argv[2]; + fieldName = argv[3]; + + io = nitf_IOHandle_create(argv[1], NITF_ACCESS_READONLY, + NITF_OPEN_EXISTING, &error); + + if (NITF_INVALID_HANDLE(io)) + { + nitf_Error_print(&error, stdout, "Exiting..."); + exit(EXIT_FAILURE); + } + + reader = nitf_Reader_construct(&error); + if (!reader) + { + nitf_Error_print(&error, stdout, "Exiting (1) ..."); + exit(EXIT_FAILURE); + } + +#if NITF_VERBOSE_READER + printf("Here are the loaded handlers\n"); + printf("* * * * * * * * * * * * * * * *\n"); + nitf_HashTable_print(reader->reg->treHandlers); + printf("* * * * * * * * * * * * * * * *\n"); +#endif + record = nitf_Reader_read(reader, io, &error); + + + lookForTREField(record->header->extendedSection, treName, fieldName); + lookForTREField(record->header->userDefinedSection, treName, fieldName); + + + + if (!nitf_Field_get(record->header->numImages, + &num, NITF_CONV_INT, NITF_INT32_SZ, &error)) + goto CATCH_ERROR; + + /* And now show the image information */ + if (num > 0) + { + + /* Walk each image and show */ + nitf_ListIterator iter = nitf_List_begin(record->images); + nitf_ListIterator end = nitf_List_end(record->images); + + while (nitf_ListIterator_notEqualTo(&iter, &end)) + { + nitf_ImageSegment *segment = + (nitf_ImageSegment *) nitf_ListIterator_get(&iter); + + lookForTREField(segment->subheader->extendedSection, treName, fieldName); + lookForTREField(segment->subheader->userDefinedSection, treName, fieldName); + nitf_ListIterator_increment(&iter); + } + } + else + { + printf("No image in file!\n"); + } + + nitf_IOHandle_close(io); + nitf_Record_destruct(&record); + + nitf_Reader_destruct(&reader); + + return 0; + +CATCH_ERROR: + printf("!!! we had a problem reading the file !!!\n"); + nitf_Error_print(&error, stdout, "Exiting..."); + exit(EXIT_FAILURE); +} + diff --git a/modules/c/nitf/tests/test_geo_utils.c b/modules/c/nitf/tests/test_geo_utils.c new file mode 100644 index 000000000..9ba7fd959 --- /dev/null +++ b/modules/c/nitf/tests/test_geo_utils.c @@ -0,0 +1,80 @@ +#include + +#define DECIMAL_LAT_STR "-12.345" +#define DECIMAL_LON_STR "+123.456" + +#define DMS_LAT_STR "123456S" +#define DMS_LON_STR "1234567E" + +int main(int argc, char**argv) +{ + + /* Try geographic stuff */ + char ll[10]; + int d, m; + double s; + double decimal; + nitf_Error e; + if (!nitf_Utils_parseGeographicString(DMS_LAT_STR, &d, &m, &s, &e)) + { + nitf_Error_print(&e, stdout, "Exiting..."); + exit(EXIT_FAILURE); + } + decimal = nitf_Utils_geographicToDecimal(d, m, s); + printf("DMS: [%s]\n", DMS_LAT_STR); + printf("\tSeparated: %d %d %f\n", d, m, s); + nitf_Utils_geographicLatToCharArray(d, m, s, ll); + printf("\tRe-formatted: [%s]\n", ll); + + printf("\tAs decimal: %f\n", decimal); + nitf_Utils_decimalLatToGeoCharArray(decimal, ll); + printf("\tRe-formatted (as decimal): [%s]\n", ll); + + /* Now convert it back */ + nitf_Utils_decimalToGeographic(decimal, &d, &m, &s); + printf("\tRound trip: %d %d %f\n", d, m, s); + + + + + if (!nitf_Utils_parseGeographicString(DMS_LON_STR, &d, &m, &s, &e)) + { + nitf_Error_print(&e, stdout, "Exiting..."); + exit(EXIT_FAILURE); + } + decimal = nitf_Utils_geographicToDecimal(d, m, s); + printf("DMS: [%s]\n", DMS_LON_STR); + printf("\tSeparated: %d %d %f\n", d, m, s); + nitf_Utils_geographicLonToCharArray(d, m, s, ll); + printf("\tRe-formatted: [%s]\n", ll); + printf("\tAs decimal: %f\n", decimal); + nitf_Utils_decimalLonToGeoCharArray(decimal, ll); + printf("\tRe-formatted (as decimal): [%s]\n", ll); + + /* Now convert it back */ + nitf_Utils_decimalToGeographic(decimal, &d, &m, &s); + printf("\tRound trip: %d %d %f\n", d, m, s); + + + + /* Try decimal stuff */ + if (!nitf_Utils_parseDecimalString(DECIMAL_LAT_STR, &decimal, &e)) + { + nitf_Error_print(&e, stdout, "Exiting..."); + exit(EXIT_FAILURE); + } + printf("Decimal: [%s]\n", DECIMAL_LAT_STR); + nitf_Utils_decimalLatToCharArray(decimal, ll); + printf("\tRe-formatted: [%s]\n", ll); + + /* Try decimal stuff */ + if (!nitf_Utils_parseDecimalString(DECIMAL_LON_STR, &decimal, &e)) + { + nitf_Error_print(&e, stdout, "Exiting..."); + exit(EXIT_FAILURE); + } + printf("Decimal: [%s]\n", DECIMAL_LON_STR); + nitf_Utils_decimalLonToCharArray(decimal, ll); + printf("\tRe-formatted: [%s]\n", ll); + return 0; +} diff --git a/modules/c/nitf/tests/test_hash_table.key_val b/modules/c/nitf/tests/test_hash_table.key_val new file mode 100644 index 000000000..14da302f5 --- /dev/null +++ b/modules/c/nitf/tests/test_hash_table.key_val @@ -0,0 +1,4 @@ +This key +That also_a_key +Hello Dan + diff --git a/modules/c/nitf/tests/test_hash_table.search_key b/modules/c/nitf/tests/test_hash_table.search_key new file mode 100644 index 000000000..e53980ab1 --- /dev/null +++ b/modules/c/nitf/tests/test_hash_table.search_key @@ -0,0 +1,4 @@ +search +This +That + diff --git a/modules/c/nitf/tests/test_hash_table_1.c b/modules/c/nitf/tests/test_hash_table_1.c new file mode 100644 index 000000000..f43e27dba --- /dev/null +++ b/modules/c/nitf/tests/test_hash_table_1.c @@ -0,0 +1,157 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + + +/* For this first test case, the DATA is a simple char* */ +/* This case should be trivial since a data pointer is */ +/* always the same size in C */ + +int main(int argc, char** argv) +{ + /* An error to populate on failure */ + nitf_Error error; + /* A hash table */ + nitf_HashTable* hashTable; + /* The hash table configurator */ + FILE* config; + + /* The search file -- look for this text */ + FILE* search; + + /* A key buffer */ + char keyBuf[512] = ""; + + /* A value buffer */ + char valueBuf[512] = ""; + + /* Construct the hash table */ + hashTable = nitf_HashTable_construct(4, &error); + + /* Make sure we got it */ + if (!hashTable) + { + /* This call is like perror() */ + nitf_Error_print(&error, stderr, "Exiting..."); + } + + /* We didnt allocate the valueBuf -- its static */ + /* As a result, we need to notify our hash table NOT to */ + /* destroy it on failure */ + nitf_HashTable_setPolicy(hashTable, NITF_DATA_RETAIN_OWNER); + + /* Make sure our key value file and search file exist */ + if (argc != 3) + { + printf("Usage: %s \n", argv[0]); + exit(EXIT_FAILURE); + } + /* Open our config file, this contains the key-value pairs we */ + /* will insert into our hash, in the order key[tab]value */ + config = fopen( argv[1], "r" ); + + if ( !config ) + { + /* If we didnt open, freak out at the user */ + printf("Could not find file [%s]\n", argv[1]); + exit(EXIT_FAILURE); + } + /* Scan the configuration file, and read into the buffers */ + while ( fscanf( config, "%s\t%s\n", keyBuf, valueBuf) != EOF ) + { + + printf("Read Key: %s\n", keyBuf); + + /* Now comes the important part -- insert */ + if (!nitf_HashTable_insert(hashTable, keyBuf, valueBuf, &error)) + { + nitf_Error_fprintf(&error, stderr, "While trying to insert [%s]\n", + keyBuf); + /* And here is the REAL test, can it delete properly!! */ + nitf_HashTable_destruct(&hashTable); + exit(EXIT_FAILURE); + } + + /* Be nice -- reset buffers */ + memset(keyBuf, 0, 512); + memset(valueBuf, 0, 512); + + } + /* Close the configurator */ + fclose( config ); + + /* Now, lets be expansive and print the list */ + nitf_HashTable_print(hashTable); + + /* Open the search file -- this contains keys to search for */ + search = fopen( argv[2], "r" ); + + /* If we couldnt open */ + if ( !search ) + { + /* Die a sad death */ + printf("Could not find file [%s]\n", argv[1]); + + /* We've already created the hash table, now we have to dump it */ + nitf_HashTable_destruct(&hashTable); + exit(EXIT_FAILURE); + + } + /* Reset the key again, we need it one more time */ + memset(keyBuf, 0, 512); + while ( fscanf( search, "%s\n", keyBuf) != EOF ) + { + /* A find gives us back a pair, just like in a std::map */ + nitf_Pair* where = NULL; + + printf("Searching for key [%s] in hash table\n", + keyBuf); + + /* Find the key/value pair */ + where = nitf_HashTable_find(hashTable, keyBuf); + + /* We didnt get it */ + if ( where == NULL ) + { + printf("\t[%s] Search unsuccessful. No such key\n", + keyBuf); + } + /* Its there in the hash!! */ + else + { + printf("\t[%s] Located the value! Value: [%s]\n", + keyBuf, + (char*)where->data); + } + + /* Reset the key buffer */ + memset(keyBuf, 0, 512); + + } + /* Close the search file */ + fclose(search); + + /* Destroy our hash table */ + nitf_HashTable_destruct(&hashTable); + return 0; +} diff --git a/modules/c/nitf/tests/test_hash_table_2.c b/modules/c/nitf/tests/test_hash_table_2.c new file mode 100644 index 000000000..d54f9b8f4 --- /dev/null +++ b/modules/c/nitf/tests/test_hash_table_2.c @@ -0,0 +1,129 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + +typedef struct _TestData +{ + char raw[512]; + int len; +} +TestData; +/* For this first test case, the DATA is a simple char* */ +/* This case should be trivial since a data pointer is */ +/* always the same size in C */ + +int main(int argc, char** argv) +{ + nitf_HashTable* hashTable; + int i; + FILE* config; + FILE* search; + char keyBuf[512] = ""; + char valueBuf[512] = ""; + TestData* allocVal; + + hashTable = nitf_HashTable_construct(50); + + nitf_HashTable_initDefaults(hashTable); + if (argc != 3) + { + printf("Usage: %s \n", argv[0]); + exit(EXIT_FAILURE); + } + + config = fopen( argv[1], "r" ); + if ( !config ) + { + printf("Could not find file [%s]\n", argv[1]); + exit(EXIT_FAILURE); + } + while ( fscanf( config, "%s\t%s\n", keyBuf, valueBuf) != EOF ) + { + + printf("While reading file:\n"); + printf("----------------------------\n"); + printf("Read Key: %s\n", keyBuf); + + allocVal = (TestData*)malloc(sizeof(TestData)); + + /* Initialize it with garbage */ + + memset(allocVal->raw, '?', 512); + allocVal->len = strlen(valueBuf); + /* This string is NOT NULL terminated */ + memcpy(allocVal->raw, valueBuf, allocVal->len); + + + nitf_HashTable_insert(hashTable, keyBuf, allocVal); + /* Reset buffers */ + memset(keyBuf, 0, 512); + memset(valueBuf, 0, 512); + + } + fclose( config ); + + + search = fopen( argv[2], "r" ); + if ( !search ) + { + printf("Could not find file [%s]\n", argv[1]); + exit(EXIT_FAILURE); + } + memset(keyBuf, 0, 512); + while ( fscanf( search, "%s\n", keyBuf) != EOF ) + { + nitf_Pair* where = NULL; + printf("Searching for key [%s] in hash table\n", + keyBuf); + + if ( !nitf_HashTable_exists(hashTable, keyBuf) ) + { + printf("Warning: no key found [%s] in exists() call\n", + keyBuf); + } + + where = nitf_HashTable_find(hashTable, keyBuf); + if ( where == NULL ) + { + printf("\t[%s] Search unsuccessful. No such key\n", + keyBuf); + } + else + { + TestData* testData = (TestData*)where->data; + char buf[512]; + memset(buf, 0, 512); + memcpy(buf, testData->raw, testData->len); + printf("\t[%s] Located the value! Value: [%s]\n", + keyBuf, + buf); + } + + + memset(keyBuf, 0, 512); + + } + fclose(search); + nitf_HashTable_destruct(&hashTable); + return 0; +} diff --git a/modules/c/nitf/tests/test_hash_table_clone.c b/modules/c/nitf/tests/test_hash_table_clone.c new file mode 100644 index 000000000..cb037dd1f --- /dev/null +++ b/modules/c/nitf/tests/test_hash_table_clone.c @@ -0,0 +1,119 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + +/* The error is just to fulfill the interface */ +/* I hand it NULL! */ +char* clone_string(char* data, nitf_Error* error) +{ + + int data_len = strlen(data); + char* new_data = (char*)NITF_MALLOC( data_len + 1); + printf("Cloning '%s'...\n", data); + new_data[ data_len ] = 0; + assert(new_data); + strcpy(new_data, data); + return new_data; +} + + +/* For this first test case, the DATA is a simple char* */ +/* This case should be trivial since a data pointer is */ +/* always the same size in C */ + +int main(int argc, char** argv) +{ + /* An error to populate on failure */ + nitf_Error error; + /* A hash table */ + nitf_HashTable* hashTable; + /* A clone */ + nitf_HashTable* dolly = NULL; + + + /* Construct the hash table */ + hashTable = nitf_HashTable_construct(4, &error); + + /* Make sure we got it */ + if (!hashTable) + { + /* This call is like perror() */ + nitf_Error_print(&error, stderr, "Exiting..."); + } + + /* We didnt allocate the valueBuf -- its static */ + /* As a result, we need to notify our hash table NOT to */ + /* destroy it on failure */ + nitf_HashTable_setPolicy(hashTable, NITF_DATA_ADOPT); + + /* Make sure our key value file and search file exist */ + if ( (argc % 2 ) == 0 ) + { + printf("Usage: %s .. \n", argv[0]); + exit(EXIT_FAILURE); + } + + { + int i; + for (i = 1; i < argc; i += 2) + { + if (!nitf_HashTable_insert(hashTable, + argv[i], + clone_string(argv[i+1], + NULL), &error)) + { + nitf_Error_print(&error, stderr, "Insert!"); + } + } + } + + + dolly = nitf_HashTable_clone(hashTable, + (NITF_DATA_ITEM_CLONE)clone_string, + &error); + if (!dolly) + { + nitf_Error_print(&error, stderr, "Dolly died..."); + } + + assert(nitf_HashTable_insert(dolly, "Cracked", clone_string("Hash", NULL), + &error)); + + + printf("[hashTable]:\n"); + /* Now, lets be expansive and print the hash */ + nitf_HashTable_print(hashTable); + + + printf("[dolly]:\n"); + /* And lets print the clone */ + nitf_HashTable_print(dolly); + + + /* Destroy our hash table */ + nitf_HashTable_destruct(&hashTable); + /* Destroy our hash table */ + nitf_HashTable_destruct(&dolly); + + return 0; +} diff --git a/modules/c/nitf/tests/test_image_loading.c b/modules/c/nitf/tests/test_image_loading.c new file mode 100644 index 000000000..051b81c63 --- /dev/null +++ b/modules/c/nitf/tests/test_image_loading.c @@ -0,0 +1,426 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + +/* + * Take a buffer of memory that we read out of a NITF segment + * and write it one of two-ways. + * + * For non RGB 24-bit true-color data, write each band separately. + * This demonstrates the typical, non-accelerated, generic read. + * + * For 24-bit true-color, if its band interleaved by pixel (mode 'P') + * demonstrate accelerated mode, and read without de-interleaving pixels, + * then write it to one big image as is. + * + */ +void writeImage(nitf_ImageSegment * segment, + char *imageName, + nitf_ImageReader * deserializer, + int imageNumber, + nitf_Uint32 rowSkipFactor, + nitf_Uint32 columnSkipFactor, + NITF_BOOL optz, + nitf_Error * error) +{ + + nitf_Uint32 nBits, nBands, xBands, nRows, nColumns; + size_t subimageSize; + nitf_SubWindow *subimage; + unsigned int i; + int padded; + nitf_Uint8 **buffer = NULL; + nitf_Uint32 band; + nitf_Uint32 *bandList = NULL; + + nitf_DownSampler *pixelSkip; + + /* TODO, replace these macros! */ + NITF_TRY_GET_UINT32(segment->subheader->numBitsPerPixel, &nBits, + error); + NITF_TRY_GET_UINT32(segment->subheader->numImageBands, &nBands, error); + NITF_TRY_GET_UINT32(segment->subheader->numMultispectralImageBands, + &xBands, error); + nBands += xBands; + NITF_TRY_GET_UINT32(segment->subheader->numRows, &nRows, error); + NITF_TRY_GET_UINT32(segment->subheader->numCols, &nColumns, error); + subimageSize = (nRows / rowSkipFactor) * (nColumns / columnSkipFactor) + * NITF_NBPP_TO_BYTES(nBits); + + printf("Image number: %d\n", imageNumber); + printf("NBANDS -> %d\n" + "XBANDS -> %d\n" + "NROWS -> %d\n" + "NCOLS -> %d\n" + "PVTYPE -> %.*s\n" + "NBPP -> %.*s\n" + "ABPP -> %.*s\n" + "PJUST -> %.*s\n" + "IMODE -> %.*s\n" + "NBPR -> %.*s\n" + "NBPC -> %.*s\n" + "NPPBH -> %.*s\n" + "NPPBV -> %.*s\n" + "IC -> %.*s\n" + "COMRAT -> %.*s\n", + nBands, + xBands, + nRows, + nColumns, + (int)segment->subheader->pixelValueType->length, + segment->subheader->pixelValueType->raw, + (int)segment->subheader->numBitsPerPixel->length, + segment->subheader->numBitsPerPixel->raw, + (int)segment->subheader->actualBitsPerPixel->length, + segment->subheader->actualBitsPerPixel->raw, + (int)segment->subheader->pixelJustification->length, + segment->subheader->pixelJustification->raw, + (int)segment->subheader->imageMode->length, + segment->subheader->imageMode->raw, + (int)segment->subheader->numBlocksPerRow->length, + segment->subheader->numBlocksPerRow->raw, + (int)segment->subheader->numBlocksPerCol->length, + segment->subheader->numBlocksPerCol->raw, + (int)segment->subheader->numPixelsPerHorizBlock->length, + segment->subheader->numPixelsPerHorizBlock->raw, + (int)segment->subheader->numPixelsPerVertBlock->length, + segment->subheader->numPixelsPerVertBlock->raw, + (int)segment->subheader->imageCompression->length, + segment->subheader->imageCompression->raw, + (int)segment->subheader->compressionRate->length, + segment->subheader->compressionRate->raw); + + + if (optz) + { + /* + * There is an accelerated mode for band-interleaved by pixel data. + * In that case, we assume that the user doesnt want the data + * de-interleaved into separate band buffers. To make this work + * you have to tell us that you want only one band back, + * and you have to provide us a singular buffer that is the + * actual number of bands x the pixel size. Then we will + * read the window and not de-interleave. + * To demonstrate, for RGB24 images, let's we write out the 1 band + * - this will be MUCH faster + */ + if (nBands == 3 + && segment->subheader->imageMode->raw[0] == 'P' + && strncmp("RGB", segment->subheader->imageRepresentation->raw, 3) == 0 + && NITF_NBPP_TO_BYTES(nBits) == 1 + && (strncmp("NC", segment->subheader->imageCompression->raw, 2) + || strncmp("NM", segment->subheader->imageCompression->raw, 2))) + { + subimageSize *= nBands; + nBands = 1; + printf("Using accelerated 3-band RGB mode pix-interleaved image\n"); + } + + + if (nBands == 2 + && segment->subheader->NITF_IMODE->raw[0] == 'P' + && NITF_NBPP_TO_BYTES(nBits) == 4 + && segment->subheader->bandInfo[0]->NITF_ISUBCAT->raw[0] == 'I' + && (strncmp("NC", segment->subheader->NITF_IC->raw, 2) + || strncmp("NM", segment->subheader->NITF_IC->raw, 2))) + { + subimageSize *= nBands; + nBands = 1; + printf("Using accelerated 2-band IQ mode pix-interleaved image\n"); + } + } + subimage = nitf_SubWindow_construct(error); + assert(subimage); + + /* + * You need a buffer for each band (unless this is an + * accelerated IQ complex or RGB read, in which case, you + * can set the number of bands to 1, and size your buffer + * accordingly to receive band-interleaved by pixel data) + */ + buffer = (nitf_Uint8 **) NITF_MALLOC(nBands * sizeof(nitf_Uint8*)); + + /* An iterator for bands */ + band = 0; + + /* + * This tells us what order to give you bands in. Normally + * you just want it in the order of the banding. For example, + * in a non-accelerated band-interleaved by pixel cases, you might + * have a band of magnitude and a band of phase. If you order the + * bandList backwards, the phase buffer comes first in the output + */ + bandList = (nitf_Uint32 *) NITF_MALLOC(sizeof(nitf_Uint32 *) * nBands); + + /* This example reads all rows and cols starting at 0, 0 */ + subimage->startCol = 0; + subimage->startRow = 0; + + /* Request rows is the full rows dividied by pixel skip (usually 1) */ + subimage->numRows = nRows / rowSkipFactor; + + /* Request columns is the full columns divided by pixel skip (usually 1) */ + subimage->numCols = nColumns / columnSkipFactor; + + /* Construct our pixel skip downsampler (does nothing if skips are 1) */ + pixelSkip = nitf_PixelSkip_construct(rowSkipFactor, + columnSkipFactor, + error); + if (!pixelSkip) + { + nitf_Error_print(error, stderr, "Pixel Skip construction failed"); + goto CATCH_ERROR; + } + if (!nitf_SubWindow_setDownSampler(subimage, pixelSkip, error)) + { + nitf_Error_print(error, stderr, "Set down sampler failed"); + goto CATCH_ERROR; + } + + for (band = 0; band < nBands; band++) + bandList[band] = band; + subimage->bandList = bandList; + subimage->numBands = nBands; + + assert(buffer); + for (i = 0; i < nBands; i++) + { + buffer[i] = (nitf_Uint8 *) NITF_MALLOC(subimageSize); + assert(buffer[i]); + } + if (!nitf_ImageReader_read + (deserializer, subimage, buffer, &padded, error)) + { + nitf_Error_print(error, stderr, "Read failed"); + goto CATCH_ERROR; + } + for (i = 0; i < nBands; i++) + { + + nitf_IOHandle toFile; + char file[NITF_MAX_PATH]; + int pos; + + /* find end slash */ + for (pos = strlen(imageName) - 1; + pos && imageName[pos] != '\\' && imageName[pos] != '/'; + pos--); + + pos = pos == 0 ? pos : pos + 1; + NITF_SNPRINTF(file, NITF_MAX_PATH, + "%s_%d__%d_%d_%d_band_%d", &imageName[pos], + imageNumber, nRows / rowSkipFactor, + nColumns / columnSkipFactor, nBits, i); + /* remove decimals */ + for (pos = strlen(file) - 1; pos; pos--) + if (file[pos] == '.') + file[pos] = '_'; + strcat(file, ".out"); + printf("File: %s\n", file); + toFile = nitf_IOHandle_create(file, NITF_ACCESS_WRITEONLY, + NITF_CREATE, error); + if (NITF_INVALID_HANDLE(toFile)) + { + nitf_Error_print(error, stderr, + "IO handle creation failed for raw band"); + goto CATCH_ERROR; + } + if (!nitf_IOHandle_write(toFile, + (const char *) buffer[i], + subimageSize, error)) + { + nitf_Error_print(error, stderr, + "IO handle write failed for raw band"); + goto CATCH_ERROR; + } + nitf_IOHandle_close(toFile); + } + + /* free buffers */ + for (i = 0; i < nBands; i++) + NITF_FREE(buffer[i]); + + NITF_FREE(buffer); + NITF_FREE(bandList); + nitf_SubWindow_destruct(&subimage); + nitf_DownSampler_destruct(&pixelSkip); + + return; + +CATCH_ERROR: + /* free buffers */ + for (i = 0; i < nBands; i++) + NITF_FREE(buffer[i]); + NITF_FREE(buffer); + NITF_FREE(bandList); + printf("ERROR processing\n"); +} + +int main(int argc, char **argv) +{ + + /* This is the error we hopefully wont receive */ + nitf_Error e; + + /* Skip factors */ + nitf_Uint32 rowSkipFactor = 1; + nitf_Uint32 columnSkipFactor = 1; + + /* This is the reader */ + nitf_Reader *reader; + + /* This is the record of the file we are reading */ + nitf_Record *record; + + + /* This is the io handle we will give the reader to parse */ + nitf_IOHandle io; + + int count = 0; + int numImages; + + /* These iterators are for going through the image segments */ + nitf_ListIterator iter; + nitf_ListIterator end; + + char* inputFile; + NITF_BOOL optz = 0; + + /* If you didnt give us a nitf file, we're croaking */ + if (argc < 2) + { + printf("Usage: %s (-o)\n", argv[0]); + exit(EXIT_FAILURE); + } + + if (argc == 3) + { + optz = 1; + + if (strcmp(argv[1], "-o") == 0) + { + inputFile = argv[2]; + } + else if (strcmp(argv[2], "-o") == 0) + { + inputFile = argv[1]; + } + else + { + printf("Usage: %s (-o)\n", argv[0]); + exit(EXIT_FAILURE); + + } + } + else + inputFile = argv[1]; + + /* You should use this function to test that you have a valid NITF */ + if (nitf_Reader_getNITFVersion( inputFile ) == NITF_VER_UNKNOWN) + { + printf("This file does not appear to be a valid NITF"); + exit(EXIT_FAILURE); + } + + reader = nitf_Reader_construct(&e); + if (!reader) + { + nitf_Error_print(&e, stderr, "Reader creation failed"); + exit(EXIT_FAILURE); + } + + /* + * As of 2.5, you do not have to use an IOHandle if you use + * readIO instead of read() + */ + io = nitf_IOHandle_create(inputFile, + NITF_ACCESS_READONLY, + NITF_OPEN_EXISTING, &e); + + if (NITF_INVALID_HANDLE(io)) + { + nitf_Error_print(&e, stderr, "IO creation failed"); + exit(EXIT_FAILURE); + } + + /* Read the file */ + record = nitf_Reader_read(reader, io, &e); + if (!record) + { + nitf_Error_print(&e, stderr, "Read failed"); + nitf_IOHandle_close(io); + nitf_Reader_destruct(&reader); + exit(EXIT_FAILURE); + } + + numImages = nitf_Record_getNumImages(record, &e); + + if ( NITF_INVALID_NUM_SEGMENTS( numImages ) ) + { + nitf_Error_print(&e, stderr, "Failed to get the number of images"); + nitf_IOHandle_close(io); + nitf_Reader_destruct(&reader); + nitf_Record_destruct( &record ); + exit(EXIT_FAILURE); + } + + /* Set the iterator to traverse the list of image segments */ + iter = nitf_List_begin(record->images); + + /* And set this one to the end, so we'll know when we're done! */ + end = nitf_List_end(record->images); + + for (count = 0; count < numImages; ++count) + { + nitf_ImageSegment *imageSegment = + (nitf_ImageSegment *) nitf_ListIterator_get(&iter); + + nitf_ImageReader *deserializer = + nitf_Reader_newImageReader(reader, count, NULL, &e); + + if (!deserializer) + { + nitf_Error_print(&e, stderr, "Couldnt spawn deserializer"); + exit(EXIT_FAILURE); + } + + printf("Writing image %d... ", count); + + /* Write the thing out */ + writeImage(imageSegment, inputFile, deserializer, count, + rowSkipFactor, columnSkipFactor, optz, &e); + + nitf_ImageReader_destruct(&deserializer); + + printf("done.\n"); + + /* Increment the iterator so we can continue */ + nitf_ListIterator_increment(&iter); + } + + nitf_Record_destruct(&record); + nitf_Reader_destruct(&reader); + nitf_IOHandle_close(io); + + return 0; +} diff --git a/modules/c/nitf/tests/test_image_source.c b/modules/c/nitf/tests/test_image_source.c new file mode 100644 index 000000000..2e198eeb6 --- /dev/null +++ b/modules/c/nitf/tests/test_image_source.c @@ -0,0 +1,140 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + +#define MEMBUF "ABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABC" +#define MEMSIZE strlen(MEMBUF) +#define NUM_BANDS 3 +#define FILENM "test_file.src" +void print_band(char* band, const char* s, int size) +{ + int i; + printf("Band %s: [", s); + for (i = 0; i < size; i++) + { + printf("%c", band[i]); + } + printf("]\n"); +} + +nitf_IOHandle prepare_io() +{ + /* First we'll create the file for them... */ + nitf_Error error; + nitf_IOHandle handle = nitf_IOHandle_create(FILENM, NITF_ACCESS_WRITEONLY, NITF_CREATE, &error); + if (NITF_INVALID_HANDLE(handle)) + { + nitf_Error_print(&error, stdout, "Quitting!"); + exit(EXIT_FAILURE); + } + /* And we'll write our buffer out */ + nitf_IOHandle_write(handle, MEMBUF, MEMSIZE, &error); + nitf_IOHandle_close(handle); + + + /* Now we'll reopen in readonly fashion */ + handle = nitf_IOHandle_create(FILENM, NITF_ACCESS_READONLY, NITF_CREATE, &error); + if (NITF_INVALID_HANDLE(handle)) + { + nitf_Error_print(&error, stdout, "Quitting!"); + exit(EXIT_FAILURE); + } + return handle; +} + +int main(int argc, char **argv) +{ + /* Get the error object */ + nitf_Error error; + int bandSize = MEMSIZE / NUM_BANDS; + nitf_IOHandle handle = prepare_io(); + nitf_ImageSource* is = nitf_ImageSource_construct(&error); + char *band_0; char* band_1; char* band_2; + + int numBytesPerPix = 1; + + /* Construct the band sources */ + + + nitf_BandSource* bs0 = nitf_FileSource_construct(handle, 0, numBytesPerPix, + NUM_BANDS - 1, &error); + nitf_BandSource* bs1 = nitf_FileSource_construct(handle, 1, numBytesPerPix, + NUM_BANDS - 1, &error); + nitf_BandSource* bs2 = nitf_FileSource_construct(handle, 2, numBytesPerPix, + NUM_BANDS - 1, &error); + + + assert( nitf_IOHandle_getSize(handle, &error) == MEMSIZE ); + + if (!is) goto CATCH_ERROR; + + assert( nitf_ImageSource_addBand(is, bs0, &error)); + assert( nitf_ImageSource_addBand(is, bs1, &error)); + assert( nitf_ImageSource_addBand(is, bs2, &error)); + + /* Construct in memory band buffers -- for testing -- 0 terminate strings */ + band_0 = (char*)NITF_MALLOC(bandSize + 1); band_0[bandSize] = 0; + band_1 = (char*)NITF_MALLOC(bandSize + 1); band_1[bandSize] = 1; + band_2 = (char*)NITF_MALLOC(bandSize + 1); band_2[bandSize] = 2; + + + bs0 = nitf_ImageSource_getBand(is, 0, &error); assert(bs0); + bs1 = nitf_ImageSource_getBand(is, 1, &error); assert(bs1); + bs2 = nitf_ImageSource_getBand(is, 2, &error); assert(bs2); + + /* Read half of the info for one band. This makes sure that we */ + /* are capable of picking up where we left off */ + bs0->iface->read(bs0->data, band_0, (MEMSIZE / NUM_BANDS / 2), &error); + bs1->iface->read(bs1->data, band_1, (MEMSIZE / NUM_BANDS / 2), &error); + bs2->iface->read(bs2->data, band_2, (MEMSIZE / NUM_BANDS / 2), &error); + print_band(band_0, "1: half", MEMSIZE / NUM_BANDS / 2); + print_band(band_1, "2: half", MEMSIZE / NUM_BANDS / 2); + print_band(band_2, "3: half", MEMSIZE / NUM_BANDS / 2); + /* Pick up where we left off and keep going */ + bs0->iface->read(bs0->data, &band_0[MEMSIZE / NUM_BANDS / 2], (MEMSIZE / NUM_BANDS / 2), &error); + bs1->iface->read(bs1->data, &band_1[MEMSIZE / NUM_BANDS / 2], (MEMSIZE / NUM_BANDS / 2), &error); + bs2->iface->read(bs2->data, &band_2[MEMSIZE / NUM_BANDS / 2], (MEMSIZE / NUM_BANDS / 2), &error); + + /* Now we would like to verify the results of our reading */ + + /* The first three bands should be all of the same letter B1=A, B2=B, B3=C*/ + print_band(band_0, "1", MEMSIZE / NUM_BANDS); + print_band(band_1, "2", MEMSIZE / NUM_BANDS); + print_band(band_2, "3", MEMSIZE / NUM_BANDS); + + + + NITF_FREE(band_0); + NITF_FREE(band_1); + NITF_FREE(band_2); + + nitf_BandSource_destruct(&bs0); + nitf_BandSource_destruct(&bs1); + nitf_BandSource_destruct(&bs2); + return 0; + +CATCH_ERROR: + nitf_Error_print(&error, stdout, "Quitting"); + exit(EXIT_FAILURE); + +} diff --git a/modules/c/nitf/tests/test_imsub_clone.c b/modules/c/nitf/tests/test_imsub_clone.c new file mode 100644 index 000000000..5c5b32939 --- /dev/null +++ b/modules/c/nitf/tests/test_imsub_clone.c @@ -0,0 +1,269 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + +#define SHOW(X) printf("%s=[%s]\n", #X, X) +#define SHOWI(X) printf("%s=[%ld]\n", #X, X) +#define SHOWLL(X) printf("%s=[%lld]\n", #X, X) +#define SHOW_IMSUB(X) printf("Image Subheader [%s]:\n", #X); showImageSubheader(X) + +#define SHOW_VAL(X) printf("%s=[%.*s]\n", #X, ((X==0)?8:((X->raw==0)?5:(int)X->length)), ((X==0)?"(nulptr)":((X->raw==0)?"(nul)":X->raw))) + +void showFileHeader(nitf_FileHeader* header) +{ + unsigned int i; + nitf_Uint32 num; + nitf_Error error; + nitf_Uint32 len; + nitf_Uint64 dataLen; + + SHOW_VAL( header->fileHeader ); + SHOW_VAL( header->fileVersion ); + SHOW_VAL( header->complianceLevel ); + SHOW_VAL( header->systemType ); + SHOW_VAL( header->originStationID ); + SHOW_VAL( header->fileDateTime ); + SHOW_VAL( header->fileTitle ); + SHOW_VAL( header->classification ); + SHOW_VAL( header->messageCopyNum ); + SHOW_VAL( header->messageNumCopies ); + SHOW_VAL( header->encrypted ); + SHOW_VAL( header->backgroundColor ); + SHOW_VAL( header->originatorName ); + SHOW_VAL( header->originatorPhone ); + + SHOW_VAL( header->fileLength ); + SHOW_VAL( header->headerLength ); + + /* Attention: If the classification is U, the security group */ + /* section should be empty! For that reason, we wont print */ + /* The security group for now */ + + SHOW_VAL( header->securityGroup->classificationSystem ); + SHOW_VAL( header->securityGroup->codewords ); + SHOW_VAL( header->securityGroup->controlAndHandling ); + SHOW_VAL( header->securityGroup->releasingInstructions ); + SHOW_VAL( header->securityGroup->declassificationType ); + SHOW_VAL( header->securityGroup->declassificationDate ); + SHOW_VAL( header->securityGroup->declassificationExemption ); + SHOW_VAL( header->securityGroup->downgrade ); + SHOW_VAL( header->securityGroup->downgradeDateTime ); + SHOW_VAL( header->securityGroup->classificationText ); + SHOW_VAL( header->securityGroup->classificationAuthorityType ); + SHOW_VAL( header->securityGroup->classificationAuthority ); + SHOW_VAL( header->securityGroup->classificationReason ); + SHOW_VAL( header->securityGroup->securitySourceDate ); + SHOW_VAL( header->securityGroup->securityControlNumber ); + + + NITF_TRY_GET_UINT32(header->numImages, &num, &error); + printf("The number of IMAGES contained in this file [%ld]\n", (long)num); + for (i = 0; i < num; i++) + { + NITF_TRY_GET_UINT32(header->imageInfo[i]->lengthSubheader, &len, &error); + NITF_TRY_GET_UINT64(header->imageInfo[i]->lengthData, &dataLen, &error); + printf("\tThe length of IMAGE subheader [%d]: %ld bytes\n", + i, (long)len); + printf("\tThe length of the IMAGE data: %llu bytes\n\n", + dataLen); + } + + return; + +CATCH_ERROR: + printf("Error processing\n"); +} + +void showImageSubheader(nitf_ImageSubheader* imsub) +{ + int q; /* iterator */ + int nbands, xbands; + nitf_Error error; + nitf_ListIterator iter, end; + + printf("Read image into imsub\n"); + SHOW_VAL( imsub->filePartType ); + SHOW_VAL( imsub->imageId ); + SHOW_VAL( imsub->imageDateAndTime ); + SHOW_VAL( imsub->targetId ); + SHOW_VAL( imsub->imageTitle ); + SHOW_VAL( imsub->imageSecurityClass ); + SHOW_VAL( imsub->encrypted ); + SHOW_VAL( imsub->imageSource ); + SHOW_VAL( imsub->numRows ); + SHOW_VAL( imsub->numCols ); + SHOW_VAL( imsub->pixelValueType ); + SHOW_VAL( imsub->imageRepresentation ); + SHOW_VAL( imsub->imageCategory ); + SHOW_VAL( imsub->actualBitsPerPixel ); + SHOW_VAL( imsub->pixelJustification ); + SHOW_VAL( imsub->imageCoordinateSystem ); + SHOW_VAL( imsub->cornerCoordinates ); + + SHOW_VAL( imsub->numImageComments ); + iter = nitf_List_begin(imsub->imageComments); + end = nitf_List_end(imsub->imageComments); + while (nitf_ListIterator_notEqualTo(&iter, &end)) + { + nitf_Field* commentField = (nitf_Field*) nitf_ListIterator_get(&iter); + SHOW_VAL(commentField); + nitf_ListIterator_increment(&iter); + } + + SHOW_VAL( imsub->imageCompression ); + SHOW_VAL( imsub->compressionRate ); + + SHOW_VAL( imsub->numImageBands ); + SHOW_VAL( imsub->numMultispectralImageBands ); + + NITF_TRY_GET_UINT32(imsub->numImageBands, &nbands, &error); + NITF_TRY_GET_UINT32(imsub->numMultispectralImageBands, &xbands, &error); + nbands += xbands; + for (q = 0; q < nbands; q++) + { + SHOW_VAL( imsub->bandInfo[q]->representation); + SHOW_VAL( imsub->bandInfo[q]->subcategory ); + SHOW_VAL( imsub->bandInfo[q]->imageFilterCondition ); + SHOW_VAL( imsub->bandInfo[q]->imageFilterCode ); + SHOW_VAL( imsub->bandInfo[q]->numLUTs ); + SHOW_VAL( imsub->bandInfo[q]->bandEntriesPerLUT ); + } + + /* Skip band stuff for now */ + SHOW_VAL( imsub->imageSyncCode ); + SHOW_VAL( imsub->imageMode ); + SHOW_VAL( imsub->numBlocksPerRow ); + SHOW_VAL( imsub->numBlocksPerCol ); + SHOW_VAL( imsub->numPixelsPerHorizBlock ); + SHOW_VAL( imsub->numPixelsPerVertBlock ); + SHOW_VAL( imsub->numBitsPerPixel ); + SHOW_VAL( imsub->imageDisplayLevel ); + SHOW_VAL( imsub->imageAttachmentLevel ); + SHOW_VAL( imsub->imageLocation ); + SHOW_VAL( imsub->imageMagnification ); + SHOW_VAL( imsub->userDefinedImageDataLength ); + SHOW_VAL( imsub->userDefinedOverflow ); + SHOW_VAL( imsub->extendedHeaderLength ); + SHOW_VAL( imsub->extendedHeaderOverflow ); + + return; + +CATCH_ERROR: + printf("Error processing\n"); + +} + +int main(int argc, char **argv) +{ + /* This is the reader object */ + nitf_Reader* reader; + nitf_Record* record; + /* The IO handle */ + nitf_IOHandle io; + /* Get the error object */ + nitf_Error error; + + /* Check argv and make sure we are happy */ + if ( argc != 2 ) + { + printf("Usage: %s \n", argv[0]); + exit(EXIT_FAILURE); + } + + io = nitf_IOHandle_create(argv[1], + NITF_ACCESS_READONLY, + NITF_OPEN_EXISTING, + &error); + if ( NITF_INVALID_HANDLE( io ) ) + { + nitf_Error_print(&error, stdout, "Exiting..."); + exit( EXIT_FAILURE ); + } + + reader = nitf_Reader_construct(&error); + if (!reader) + { + nitf_Error_print(&error, stdout, "Exiting (1) ..."); + exit( EXIT_FAILURE ); + } + + printf("Here are the loaded handlers\n"); + printf("* * * * * * * * * * * * * * * *\n"); + { + nitf_PluginRegistry* reg = nitf_PluginRegistry_getInstance(&error); + nitf_HashTable_print( reg->treHandlers); + } + printf("* * * * * * * * * * * * * * * *\n"); + + record = nitf_Reader_read(reader, io, &error); + if (!record) + { + nitf_Error_print(&error, stderr, "Failed to read the file"); + exit(EXIT_FAILURE); + + } + + /* Now show the header */ + showFileHeader(record->header); + + /* And now show the image information */ + if (record->header->numImages) + { + + /* Walk each image and show */ + nitf_ListIterator iter = nitf_List_begin(record->images); + nitf_ListIterator end = nitf_List_end(record->images); + + while ( nitf_ListIterator_notEqualTo(&iter, &end) ) + { + nitf_ImageSegment* segment = + (nitf_ImageSegment*)nitf_ListIterator_get(&iter); + + nitf_ImageSubheader* dolly = + nitf_ImageSubheader_clone(segment->subheader, &error); + if (!dolly) + { + nitf_Error_print(&error, stdout, "During cloning!"); + exit(EXIT_FAILURE); + } + + SHOW_IMSUB(segment->subheader); + SHOW_IMSUB(dolly); + + nitf_ImageSubheader_destruct(&dolly); + + nitf_ListIterator_increment(&iter); + + } + } + else + { + printf("No image in file!\n"); + } + + nitf_IOHandle_close(io); + nitf_Record_destruct(&record); + nitf_Reader_destruct(&reader); + + return 0; +} diff --git a/modules/c/nitf/tests/test_insert_raw_xmltre.c b/modules/c/nitf/tests/test_insert_raw_xmltre.c new file mode 100644 index 000000000..8845c6652 --- /dev/null +++ b/modules/c/nitf/tests/test_insert_raw_xmltre.c @@ -0,0 +1,677 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + + +#include + +/* + * Warning! In order for this test to work properly, you must not + * set the NITF_PLUGIN_PATH to use the XMLTRE plugin provided in + * the external/examples area! This will load an entirely different + * handler, which will not use TRE descriptions at all! + * + * This test case adds a TRE called XMLTRE to the header. The user + * is required to provide an XML file that can be inserted into the + * body of the TRE. + * + * This test does cover some basic insertion functionality, but primarily + * it is useful because it can add arbitrary XML to the file header, + * which is helpful for testing how the updated TRE interface handles XML + * data. + */ + +nitf_TRE* createXMLTRE(const char* data, const int length) +{ + nitf_TRE *tre; + nitf_Error error; + + tre = nitf_TRE_construct("XMLTRE", NITF_TRE_RAW, &error); + if (!tre) + { + nitf_Error_print(&error, stdout, "Exiting..."); + exit(EXIT_FAILURE); + } + /* TODO! Make setField const char*? */ + nitf_TRE_setField(tre, "raw_data", (char*)data, length, &error); + return tre; +} + +nitf_Record *doRead(const char *inFile); + + +#define GET_UINT32(FIELD, DATA_PTR, ERROR) \ + success = nitf_Field_get(FIELD, DATA_PTR, NITF_CONV_UINT, NITF_INT32_SZ, ERROR); \ + if (!success) goto CATCH_ERROR; + +#define GET_UINT64(FIELD, DATA_PTR, ERROR) \ + success = nitf_Field_get(FIELD, DATA_PTR, NITF_CONV_UINT, NITF_INT64_SZ, ERROR); \ + if (!success) goto CATCH_ERROR; + +/* pass in a negative number for bandNum if you don't want a band in the name */ +char *makeBandName(const char *rootFile, const char* segment, int segmentNum, int bandNum) +{ + char *file = (char *) NITF_MALLOC(NITF_MAX_PATH); + int pos; + + /* find end slash */ + for (pos = strlen(rootFile) - 1; + pos && rootFile[pos] != '\\' && rootFile[pos] != '/'; pos--); + + if (bandNum >= 0) + NITF_SNPRINTF(file, NITF_MAX_PATH, "%s__%s_%d_band_%d", + &rootFile[pos + 1], segment, segmentNum, bandNum); + else + NITF_SNPRINTF(file, NITF_MAX_PATH, "%s__%s_%d", + &rootFile[pos + 1], segment, segmentNum); + /* remove decimals */ + for (pos = strlen(file) - 1; pos; pos--) + { + if (file[pos] == '.') + { + file[pos] = '_'; + } + } + strcat(file, ".man"); + printf("File: %s\n", file); + return file; +} + +void freeBandName(char **rootFile) +{ + if (*rootFile) + { + NITF_FREE(*rootFile); + *rootFile = NULL; + + } +} + +nitf_ImageSource *setupBands(int nbands, int imageNum, + const char *inRootFile) +{ + nitf_Error error; + int i; + nitf_BandSource *bandSource; + nitf_ImageSource *iSource = nitf_ImageSource_construct(&error); + if (!iSource) + goto CATCH_ERROR; + for (i = 0; i < nbands; i++) + { + char *inFile = makeBandName(inRootFile, "img", imageNum, i); + nitf_IOHandle sourceHandle = + nitf_IOHandle_create(inFile, NITF_ACCESS_READONLY, + NITF_OPEN_EXISTING, &error); + if (NITF_INVALID_HANDLE(sourceHandle)) + goto CATCH_ERROR; + + freeBandName(&inFile); + + bandSource = nitf_FileSource_construct(sourceHandle, + 0, 0 /*gets ignored */ , 0, + &error); + if (!bandSource) + { + goto CATCH_ERROR; + } + if (!nitf_ImageSource_addBand(iSource, bandSource, &error)) + { + goto CATCH_ERROR; + } + } + return iSource; + +CATCH_ERROR: + nitf_Error_print(&error, stderr, "While constructing image source"); + exit(EXIT_FAILURE); +} + +void doWrite(nitf_Record * record, char *inRootFile, char *outFile) +{ + nitf_ListIterator iter; + + nitf_ImageWriter *iWriter; + nitf_ImageSource *iSource; + + nitf_SegmentWriter *segmentWriter; + nitf_SegmentSource *segmentSource; + + nitf_ListIterator end; + int i; + int numImages; + int numTexts; + int numDataExtensions; + nitf_Writer *writer = NULL; + nitf_Error error; + nitf_IOHandle output_io = nitf_IOHandle_create(outFile, + NITF_ACCESS_WRITEONLY, + NITF_CREATE, + &error); + + if (NITF_INVALID_HANDLE(output_io)) + { + goto CATCH_ERROR; + } + + writer = nitf_Writer_construct(&error); + if (!writer) + { + goto CATCH_ERROR; + } + if (!nitf_Writer_prepare(writer, record, output_io, &error)) + { + goto CATCH_ERROR; + } + + if (!nitf_Field_get + (record->header->numImages, &numImages, NITF_CONV_INT, + NITF_INT32_SZ, &error)) + { + nitf_Error_print(&error, stderr, "nitf::Value::get() failed"); + numImages = 0; + } + + if (!nitf_Field_get + (record->header->numTexts, &numTexts, NITF_CONV_INT, + NITF_INT32_SZ, &error)) + { + nitf_Error_print(&error, stderr, "nitf::Value::get() failed"); + numTexts = 0; + } + + if (!nitf_Field_get + (record->header->numDataExtensions, &numDataExtensions, NITF_CONV_INT, + NITF_INT32_SZ, &error)) + { + nitf_Error_print(&error, stderr, "nitf::Value::get() failed"); + numDataExtensions = 0; + } + + if (record->images) + { + end = nitf_List_end(record->images); + for (i = 0; i < numImages; i++) + { + int nbands; + nitf_ImageSegment *imseg = NULL; + iter = nitf_List_at(record->images, i); + assert(nitf_ListIterator_notEqualTo(&iter, &end)); + + imseg = (nitf_ImageSegment *) nitf_ListIterator_get(&iter); + assert(imseg); + + if (!nitf_Field_get + (imseg->subheader->numImageBands, &nbands, NITF_CONV_INT, + NITF_INT32_SZ, &error)) + goto CATCH_ERROR; + + iWriter = nitf_Writer_newImageWriter(writer, i, NULL, &error); + if (!iWriter) + { + goto CATCH_ERROR; + } + iSource = setupBands(nbands, i, inRootFile); + if (!iSource) + goto CATCH_ERROR; + if (!nitf_ImageWriter_attachSource(iWriter, iSource, &error)) + goto CATCH_ERROR; + } + } + + if (record->texts) + { + end = nitf_List_end(record->texts); + for (i = 0; i < numTexts; i++) + { + nitf_TextSegment *textSeg = NULL; + char *inFile = NULL; + nitf_IOHandle sourceHandle; + + iter = nitf_List_at(record->texts, i); + assert(nitf_ListIterator_notEqualTo(&iter, &end)); + + textSeg = (nitf_TextSegment *) nitf_ListIterator_get(&iter); + assert(textSeg); + + segmentWriter = nitf_Writer_newTextWriter(writer, i, &error); + if (!segmentWriter) + { + goto CATCH_ERROR; + } + + /* setup file */ + inFile = makeBandName(inRootFile, "text", i, -1); + sourceHandle = + nitf_IOHandle_create(inFile, NITF_ACCESS_READONLY, + NITF_OPEN_EXISTING, &error); + if (NITF_INVALID_HANDLE(sourceHandle)) + goto CATCH_ERROR; + + freeBandName(&inFile); + + segmentSource = nitf_SegmentFileSource_construct(sourceHandle, 0, 0, &error); + if (!segmentSource) + goto CATCH_ERROR; + if (!nitf_SegmentWriter_attachSource(segmentWriter, segmentSource, &error)) + goto CATCH_ERROR; + } + } + + if (record->dataExtensions) + { + end = nitf_List_end(record->dataExtensions); + for (i = 0; i < numDataExtensions; i++) + { + nitf_DESegment *DESeg = NULL; + char *inFile = NULL; + nitf_IOHandle sourceHandle; + + iter = nitf_List_at(record->dataExtensions, i); + assert(nitf_ListIterator_notEqualTo(&iter, &end)); + + DESeg = (nitf_DESegment *) nitf_ListIterator_get(&iter); + assert(DESeg); + + segmentWriter = nitf_Writer_newDEWriter(writer, i, &error); + if (!segmentWriter) + { + goto CATCH_ERROR; + } + + /* setup file */ + inFile = makeBandName(inRootFile, "DE", i, -1); + sourceHandle = + nitf_IOHandle_create(inFile, NITF_ACCESS_READONLY, + NITF_OPEN_EXISTING, &error); + if (NITF_INVALID_HANDLE(sourceHandle)) + goto CATCH_ERROR; + + freeBandName(&inFile); + + segmentSource = nitf_SegmentFileSource_construct(sourceHandle, 0, 0, &error); + if (!segmentSource) + goto CATCH_ERROR; + if (!nitf_SegmentWriter_attachSource(segmentWriter, segmentSource, &error)) + goto CATCH_ERROR; + } + } + + if (!nitf_Writer_write(writer, &error)) + { + goto CATCH_ERROR; + } + + + /*nitf_ImageSource_destruct(&iSource);*/ + nitf_IOHandle_close(output_io); + nitf_Writer_destruct(&writer); + return; +CATCH_ERROR: + nitf_Error_print(&error, stderr, "During write"); + exit(EXIT_FAILURE); +} + +int main(int argc, char **argv) +{ + + nitf_Record *record = NULL; /* a record object */ + nitf_TRE* xmltre = NULL; + char* xmlData = NULL; + + nitf_Error error; /* error object */ + + nitf_IOHandle xmlFile; + nitf_Off xmlSize; + /* Check argv and make sure we are happy */ + if (argc != 4) + { + printf("Usage: %s \n", argv[0]); + exit(EXIT_FAILURE); + } + + xmlFile = nitf_IOHandle_create(argv[3], NITF_ACCESS_READONLY, + NITF_OPEN_EXISTING, &error); + if (NITF_INVALID_HANDLE(xmlFile)) + { + perror("Failed to open xmlFile"); + exit(EXIT_FAILURE); + } + xmlSize = nitf_IOHandle_getSize(xmlFile, &error); + + xmlData = (char*)malloc(xmlSize); + nitf_IOHandle_read(xmlFile, xmlData, xmlSize, &error); + + printf("%s\n", xmlData); + nitf_IOHandle_close(xmlFile); + + record = doRead(argv[1]); + + xmltre = createXMLTRE(xmlData, xmlSize); + + if (!nitf_Extensions_appendTRE(record->header->userDefinedSection, + xmltre, &error)) + { + nitf_Error_print(&error, stdout, "Failed to add XMLTRE"); + exit(EXIT_FAILURE); + } + + + doWrite(record, argv[1], argv[2]); + nitf_Record_destruct(&record); + + return 0; +} + +/* this writes the text data from a text segment to a file */ +void writeTextData(nitf_TextSegment * segment, + const char *fileName, + nitf_SegmentReader * reader, + int textNumber, nitf_Error * error) +{ + + size_t toRead; + char * buf = NULL; + char * outName = NULL; + + nitf_IOHandle file; + + toRead = (size_t)(segment->end - segment->offset); + + buf = (char*)NITF_MALLOC(toRead + 1); + if (!buf) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + return; + } + + /* get the data */ + if (nitf_SegmentReader_read(reader, buf, toRead, error) != NITF_SUCCESS) + { + /* TODO populate error */ + goto CATCH_ERROR; + } + + outName = makeBandName(fileName, "text", textNumber, -1); + file = nitf_IOHandle_create(outName, NITF_ACCESS_WRITEONLY, + NITF_CREATE, error); + freeBandName(&outName); + + if (NITF_INVALID_HANDLE(file)) + { + goto CATCH_ERROR; + } + if (!nitf_IOHandle_write(file, (const char*)buf, toRead, error)) + goto CATCH_ERROR; + nitf_IOHandle_close(file); + +CATCH_ERROR: + if (buf) NITF_FREE(buf); + return; +} + + +void manuallyWriteImageBands(nitf_ImageSegment * segment, + const char *imageName, + nitf_ImageReader * deserializer, + int imageNumber, nitf_Error * error) +{ + char *file; + nitf_Uint32 nBits, nBands, xBands, nRows, nColumns; + size_t subimageSize; + nitf_SubWindow *subimage; + unsigned int i; + int padded; + nitf_Uint8 **buffer = NULL; + nitf_Uint32 band; + nitf_Uint32 *bandList = NULL; + + NITF_TRY_GET_UINT32(segment->subheader->numBitsPerPixel, &nBits, + error); + NITF_TRY_GET_UINT32(segment->subheader->numImageBands, &nBands, error); + NITF_TRY_GET_UINT32(segment->subheader->numMultispectralImageBands, + &xBands, error); + nBands += xBands; + NITF_TRY_GET_UINT32(segment->subheader->numRows, &nRows, error); + NITF_TRY_GET_UINT32(segment->subheader->numCols, &nColumns, error); + subimageSize = nRows * nColumns * NITF_NBPP_TO_BYTES(nBits); + + buffer = (nitf_Uint8 **) malloc(8 * nBands); + band = 0; + bandList = (nitf_Uint32 *) malloc(sizeof(nitf_Uint32 *) * nBands); + + subimage = nitf_SubWindow_construct(error); + assert(subimage); + + subimage->startCol = 0; + subimage->startRow = 0; + subimage->numRows = nRows; + subimage->numCols = nColumns; + + for (band = 0; band < nBands; band++) + bandList[band] = band; + subimage->bandList = bandList; + subimage->numBands = nBands; + + assert(buffer); + for (i = 0; i < nBands; i++) + { + buffer[i] = (nitf_Uint8 *) malloc(subimageSize); + assert(buffer[i]); + } + if (!nitf_ImageReader_read + (deserializer, subimage, buffer, &padded, error)) + { + nitf_Error_print(error, stderr, "Read failed"); + goto CATCH_ERROR; + } + for (i = 0; i < nBands; i++) + { + + nitf_IOHandle toFile; + file = makeBandName(imageName, "img", imageNumber, i); + toFile = nitf_IOHandle_create(file, NITF_ACCESS_WRITEONLY, + NITF_CREATE, error); + freeBandName(&file); + if (NITF_INVALID_HANDLE(toFile)) + { + goto CATCH_ERROR; + + } + if (!nitf_IOHandle_write(toFile, + (const char *) buffer[i], + subimageSize, error)) + + { + goto CATCH_ERROR; + } + nitf_IOHandle_close(toFile); + } + + /* free buffers */ + for (i = 0; i < nBands; i++) + { + free(buffer[i]); + } + free(buffer); + free(bandList); + nitf_SubWindow_destruct(&subimage); + return; + +CATCH_ERROR: + /* free buffers */ + for (i = 0; i < nBands; i++) + { + free(buffer[i]); + } + free(buffer); + free(bandList); + nitf_Error_print(error, stderr, "Manual write failed"); + + +} +nitf_Record *doRead(const char *inFile) +{ + /* This is the error we hopefully wont receive */ + nitf_Error e; + + /* This is the reader */ + nitf_Reader *reader; + + /* This is the record of the file we are reading */ + nitf_Record *record; + + /* This is the io handle we will give the reader to parse */ + nitf_IOHandle io; + + int count = 0; + int numImages; + int numTexts; + int numDataExtensions; + + nitf_ListIterator iter; + nitf_ListIterator end; + + + nitf_ImageSegment *imageSegment = NULL; + nitf_ImageReader *deserializer = NULL; + nitf_TextSegment *textSegment = NULL; + nitf_SegmentReader *segmentReader = NULL; + + reader = nitf_Reader_construct(&e); + if (!reader) + { + nitf_Error_print(&e, stderr, "nitf::Reader::construct() failed"); + exit(EXIT_FAILURE); + } + + /* If you did, though, we'll be nice and open it for you */ + io = nitf_IOHandle_create(inFile, + NITF_ACCESS_READONLY, + NITF_OPEN_EXISTING, &e); + + /* But, oh boy, if you gave us a bad location...! */ + if (NITF_INVALID_HANDLE(io)) + { + /* You had this coming! */ + nitf_Error_print(&e, stderr, "nitf::IOHandle::create() failed"); + exit(EXIT_FAILURE); + } + + /* Read the file */ + record = nitf_Reader_read(reader, io, &e); + if (!record) + { + nitf_Error_print(&e, stderr, "nitf::Reader::read() failed"); + exit(EXIT_FAILURE); + } + + if (!nitf_Field_get + (record->header->numImages, &numImages, NITF_CONV_INT, + NITF_INT32_SZ, &e)) + { + nitf_Error_print(&e, stderr, "nitf::Field::get() failed"); + numImages = 0; + } + + if (!nitf_Field_get + (record->header->numTexts, &numTexts, NITF_CONV_INT, + NITF_INT32_SZ, &e)) + { + nitf_Error_print(&e, stderr, "nitf::Field::get() failed"); + numTexts = 0; + } + + if (!nitf_Field_get + (record->header->numDataExtensions, &numDataExtensions, NITF_CONV_INT, + NITF_INT32_SZ, &e)) + { + nitf_Error_print(&e, stderr, "nitf::Field::get() failed"); + numDataExtensions = 0; + } + + if (record->images) + { + end = nitf_List_end(record->images); + + for (count = 0; count < numImages; ++count) + { + iter = nitf_List_at(record->images, count); + if (nitf_ListIterator_equals(&iter, &end)) + { + printf("Out of bounds on iterator [%d]!\n", count); + exit(EXIT_FAILURE); + } + imageSegment = (nitf_ImageSegment *) nitf_ListIterator_get(&iter); + deserializer = nitf_Reader_newImageReader(reader, count, NULL, &e); + if (!deserializer) + { + nitf_Error_print(&e, stderr, "Couldnt spawn deserializer"); + exit(EXIT_FAILURE); + } + printf("Writing image %d... ", count); + /* Write the thing out */ + manuallyWriteImageBands(imageSegment, inFile, deserializer, count, + &e); + + nitf_ImageReader_destruct(&deserializer); + + printf("done.\n"); + /* Increment the iterator so we can continue */ + nitf_ListIterator_increment(&iter); + } + } + + + /* loop over texts and read the data to a file */ + if (record->texts) + { + end = nitf_List_end(record->texts); + + for (count = 0; count < numTexts; ++count) + { + iter = nitf_List_at(record->texts, count); + if (nitf_ListIterator_equals(&iter, &end)) + { + printf("Out of bounds on iterator [%d]!\n", count); + exit(EXIT_FAILURE); + } + textSegment = (nitf_TextSegment *) nitf_ListIterator_get(&iter); + segmentReader = nitf_Reader_newTextReader(reader, count, &e); + if (!segmentReader) + { + nitf_Error_print(&e, stderr, "Couldnt spawn deserializer"); + exit(EXIT_FAILURE); + } + printf("Writing text %d... ", count); + /* Write the thing out */ + writeTextData(textSegment, inFile, segmentReader, count, &e); + nitf_SegmentReader_destruct(&segmentReader); + + /* Increment the iterator so we can continue */ + nitf_ListIterator_increment(&iter); + } + } + + nitf_Reader_destruct(&reader); + return record; + +} diff --git a/modules/c/nitf/tests/test_it.h b/modules/c/nitf/tests/test_it.h new file mode 100644 index 000000000..5321101ba --- /dev/null +++ b/modules/c/nitf/tests/test_it.h @@ -0,0 +1,52 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __TEST_IT_H__ +#define __TEST_IT_H__ + +/*! + * \file + * \brief Test assertion library + * + * This header provides a test assertion, TEST_IT(). + * Whenever you think you are certain of a condition or state, + * you may test it using the macro, and it will report to you + * that your assertion has failed, and where. + * + */ + +void test_it_false_assertion(const char* file, + int line, + const char* id) +{ + + printf("\tError: Test [%s] Failed at (%s, %d)\n", id, file, line); + exit(EXIT_FAILURE); +} + +#define FALSE_ASSERTION(F, L, ID ) \ + test_it_false_assertion(F, L, ID) + +#define TEST_IT(TEST) ( (TEST) ? ( printf("\tSuccess: Test [%s] Passed\n", #TEST) ) : (FALSE_ASSERTION(NITF_FILE, NITF_LINE, #TEST) ) ) + + +#endif diff --git a/modules/c/nitf/tests/test_make_pattern.c b/modules/c/nitf/tests/test_make_pattern.c new file mode 100644 index 000000000..1d5428e9e --- /dev/null +++ b/modules/c/nitf/tests/test_make_pattern.c @@ -0,0 +1,383 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +/* +* NITF file generator +* +* test_make_pattern creates a NITF file with a particular data pattern +* +* The layout of the data is defined by a test vector. This is the same +* specification format as the program test_ImageIO_writePattern +* +* The command line call is: +* +* test_make_pattern vector input output +* +* The first argument is the test vector filename and the second is the +* input file and the third is the output file +* +* The input should be a "blank" image with no segments. It is used to +* initialize the file header +* +* See the test_ImageIO programs for documenation on the test vector format +*/ + +#include + +#include "test_ImageIO.h" + +#define NUM_BANDS_MAX 50 + +/* Local functions defined after main */ + +nitf_Record *readRecord(char *file); +void setupImageSubheader( + test_nitf_ImageIOConstructArgs *args, + nitf_Record *record, nitf_ImageSegment *seg); + +nitf_ImageSource *makeImageSource( + test_nitf_ImageIOConstructArgs *args, char ***data); + +int main(int argc, char *argv[]) +{ + char *vectorFile; /* Vector file name */ + char *inputFile; /* Input file name */ + char *outputFile; /* Output file name */ + FILE *vector; /* File stream for input vector */ + /* Arguments for new */ + test_nitf_ImageIOConstructArgs *newArgs; + /* Arguments for read */ + test_nitf_ImageIOReadArgs *readArgs; + char *errorStr; /* Error string */ + + nitf_Record *record; /* Record used for input and output */ + nitf_FileHeader *fileHdr; /* File header */ + nitf_ImageSegment *imgSeg; /* New image segment */ + nitf_Writer *writer; /* Writer for output */ + nitf_ImageWriter *imgWriter; /* Image writer */ + nitf_ImageSource *imgSource; /* Image source */ + + + nitf_IOHandle out; /* Handle for output */ + nitf_Error error; /* Error object */ + nitf_Uint8 ***data; /* Generated data [band][row][col] */ + + if (argc < 4) + { + fprintf(stderr, "test_make_pattern vector input output\n"); + exit(-1); + } + vectorFile = argv[1]; + inputFile = argv[2]; + outputFile = argv[3]; + + vector = fopen(vectorFile, "r"); + if (vector == NULL) + { + fprintf(stderr, "Error opening vector file %s\n", vectorFile); + exit(-1); + } + + newArgs = test_nitf_ImageIOReadConstructArgs(vector, &errorStr); + if (newArgs == NULL) + { + fprintf(stderr, "%s\n", errorStr); + return(-1); + } + + fclose(vector); + + /* Create the input record which will be used for output */ + + record = readRecord(inputFile); + + /* Setup the image segment */ + + imgSeg = nitf_Record_newImageSegment(record, &error); + if (imgSeg == NULL) + { + nitf_Error_print(&error, stderr, "Error reading input "); + exit(EXIT_FAILURE); + } + + setupImageSubheader(newArgs, record, imgSeg); + + /* Create Image */ + + if (strcmp(newArgs->dataPattern, "brcI4") == 0) + { + data = (nitf_Uint8 ***) test_nitf_ImageIO_brcI4(newArgs, &errorStr); + if (data == NULL) + { + fprintf(stderr, "%s\n", errorStr); + exit(-1); + } + } + else if (strcmp(newArgs->dataPattern, "brcC8") == 0) + { + data = (nitf_Uint8 ***) test_nitf_ImageIO_brcC8(newArgs, &errorStr); + if (data == NULL) + { + fprintf(stderr, "%s\n", errorStr); + exit(-1); + } + } + else if (strncmp(newArgs->dataPattern, "blocks_", 7) == 0) + { + data = (nitf_Uint8 ***) test_nitf_ImageIO_block(newArgs, &errorStr); + if (data == NULL) + { + fprintf(stderr, "%s\n", errorStr); + exit(-1); + } + } + else + { + fprintf(stderr, "Invalid pattern method %s\n"); + exit(-1); + } + + /* Create output file */ + + out = nitf_IOHandle_create(outputFile, + NITF_ACCESS_WRITEONLY, NITF_CREATE | NITF_TRUNCATE, &error); + if (NITF_INVALID_HANDLE(out)) + { + nitf_Error_print(&error, stderr, "Error creating output file"); + exit(1); + } + + writer = nitf_Writer_construct(&error); + if (writer == NULL) + { + nitf_Error_print(&error, stderr, "Error creating writer object"); + exit(1); + } + + if (!nitf_Writer_prepare(writer, record, out, &error)) + { + nitf_Error_print(&error, stderr, "Error setting up write"); + exit(1); + } + + imgWriter = nitf_Writer_newImageWriter(writer, 0, &error); + if (imgWriter == NULL) + { + nitf_Error_print(&error, stderr, "Error setting up write"); + exit(1); + } + imgSource = makeImageSource(newArgs, (char ***) data); + nitf_ImageWriter_setWriteCaching(imgWriter, 1); + + if (!nitf_ImageWriter_attachSource(imgWriter, imgSource, &error)) + { + nitf_Error_print(&error, stderr, "Error setting up write"); + exit(1); + } + + + if (!nitf_Writer_write(writer, &error)) + { + nitf_Error_print(&error, stderr, "Error writing up write"); + exit(1); + } + + + /* Destroy things */ + + test_nitf_ImageIO_freeArray(data); + nitf_IOHandle_close(out); + exit(0); +} + + +/* Read in input file to create the record to use for the output */ + +nitf_Record *readRecord(char *file) +{ + nitf_IOHandle in; /* Handle for input */ + nitf_Reader *reader; /* Reader object */ + nitf_Record *record; /* The result */ + nitf_Error error; /* For errors */ + + in = nitf_IOHandle_create(file, + NITF_ACCESS_READONLY, NITF_OPEN_EXISTING, &error); + if (NITF_INVALID_HANDLE(in)) + { + nitf_Error_print(&error, stderr, "Error opening input "); + exit(EXIT_FAILURE); + } + + reader = nitf_Reader_construct(&error); + if (!reader) + { + nitf_Error_print(&error, stderr, "Error creating reader "); + exit(EXIT_FAILURE); + } + + record = nitf_Reader_read(reader, in, &error); + if (!record) + { + nitf_Error_print(&error, stderr, "Error reading input "); + exit(EXIT_FAILURE); + } + + nitf_IOHandle_close(in); + nitf_Reader_destruct(&reader); + return(record); +} + +/* Function to initialize the image subheader based on the vector */ + +void setupImageSubheader( + test_nitf_ImageIOConstructArgs *args, + nitf_Record *record, nitf_ImageSegment *seg) +{ + nitf_ImageSubheader *subheader; /* Subheader from segment */ + nitf_Uint32 nBands; /* Number of bands */ + nitf_BandInfo **bands; /* BandInfo array */ + nitf_Error errorObj; /* Error object argument */ + nitf_Uint32 i; + + subheader = seg->subheader; + nitf_Field_setUint32(subheader->numRows, args->nRows, &errorObj); + nitf_Field_setUint32(subheader->numCols, args->nColumns, &errorObj); + nitf_Field_setUint32(subheader->numImageBands, args->nBands, &errorObj); + nitf_Field_setUint32(subheader->numMultispectralImageBands, + args->nMultiBands, &errorObj); + nitf_Field_setUint32(subheader->numBlocksPerRow, + args->nBlksPerRow, &errorObj); + nitf_Field_setUint32(subheader->numBlocksPerCol, + args->nBlksPerColumn, &errorObj); + nitf_Field_setUint32(subheader->numPixelsPerVertBlock, + args->nRowsPerBlk, &errorObj); + nitf_Field_setUint32(subheader->numPixelsPerHorizBlock, + args->nColumnsPerBlk, &errorObj); + nitf_Field_setString(subheader->imageMode, args->mode, &errorObj); + nitf_Field_setString(subheader->imageCompression, + args->compression, &errorObj); + nBands = args->nBands; + if (nBands == 0) + nBands = args->nMultiBands; + + bands = (nitf_BandInfo **) NITF_MALLOC(sizeof(nitf_BandInfo *)); + if (bands == NULL) + { + nitf_Error_init(&errorObj, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + nitf_Error_print(&errorObj, stderr, "Error setting up band source "); + exit(EXIT_FAILURE); + } + + for (i = 0;i < nBands;i++) + { + bands[i] = nitf_BandInfo_construct(&errorObj); + if (bands[i] == NULL) + { + nitf_Error_print(&errorObj, stderr, "Error setting up band source "); + exit(EXIT_FAILURE); + } + + if (!nitf_BandInfo_init(bands[i], + "M", /* The band representation, Nth band */ + " ", /* The band subcategory */ + "N", /* The band filter condition */ + " ", /* The band standard image filter code */ + 0, /* The number of look-up tables */ + 0, /* The number of entries/LUT */ + NULL, /* The look-up tables */ + &errorObj)) + { + nitf_Error_print(&errorObj, stderr, "Error setting up band source "); + exit(EXIT_FAILURE); + } + } + + if (!nitf_ImageSubheader_setPixelInformation(subheader, + args->pixelType, /* Pixel value type */ + args->nBits, /* Number of bits/pixel*/ + args->nBitsActual, /* Actual number of bits/pixel */ + args->justify, /* Pixel justification */ + "MONO", /* Image representation */ + "SAR", /* Image category */ + nBands, /* Number of bands */ + bands, /* Band information object list */ + &errorObj )) + { + nitf_Error_print(&errorObj, stderr, "Error setting up band source "); + exit(EXIT_FAILURE); + } + + return; +} + +/* + Make the image source for write + + The source is built memory data sources take from data + + &(data[band][0][0]) points to the contiguous data for band "band" +*/ + +nitf_ImageSource *makeImageSource( + test_nitf_ImageIOConstructArgs *args, char ***data) +{ + nitf_ImageSource *imgSource; /* The result */ + nitf_Uint32 nBands; /* Number of bands */ + nitf_Off bandSize; /* Size of individual bands */ + nitf_Error error; /* Error object argument */ + nitf_Uint32 i; + + bandSize = (args->nRows) * (args->nColumns) * (NITF_NBPP_TO_BYTES(args->nBits)); + + imgSource = nitf_ImageSource_construct(&error); + if (imgSource == NULL) + { + nitf_Error_print(&error, stderr, "Error setting up image source "); + exit(EXIT_FAILURE); + } + + nBands = args->nBands; + if (nBands == 0) + nBands = args->nMultiBands; + + for (i = 0;i < nBands;i++) + { + nitf_DataSource * bandSrc; /* Current band data source */ + + bandSrc = nitf_MemorySource_construct( + &(data[i][0][0]), bandSize, 0, 0, 0, &error); + if (bandSrc == NULL) + { + nitf_Error_print(&error, stderr, "Error setting up band source "); + exit(EXIT_FAILURE); + } + + if (!nitf_ImageSource_addBand(imgSource, bandSrc, &error)) + { + nitf_Error_print(&error, stderr, "Error setting up band source "); + exit(EXIT_FAILURE); + } + + } + return(imgSource); +} diff --git a/modules/c/nitf/tests/test_plugin_reg_1.c b/modules/c/nitf/tests/test_plugin_reg_1.c new file mode 100644 index 000000000..314dc2748 --- /dev/null +++ b/modules/c/nitf/tests/test_plugin_reg_1.c @@ -0,0 +1,96 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + +int main(int argc, char**argv) +{ + nitf_Error error; + nitf_PluginRegistry* reg; + NITF_PLUGIN_TRE_HANDLER_FUNCTION test_main; + int bad = 0; + if (argc != 2) + { + printf("Usage: %s \n", argv[0]); + exit(EXIT_FAILURE); + } + reg = nitf_PluginRegistry_getInstance(&error); + + if (!reg) + { + nitf_Error_print(&error, stdout, "Exiting..."); + exit(EXIT_FAILURE); + } + /* Don't need this now that it is a singleton + * + * if (! nitf_PluginRegistry_load(reg, &error) ) + * { + * nitf_Error_print(&error, stdout, "Exiting..."); + * exit(EXIT_FAILURE); + * } + */ + + nitf_HashTable_print(reg->treHandlers); + + test_main = + nitf_PluginRegistry_retrieveTREHandler(reg, + argv[1], + &bad, + &error); + + + if (bad) + { + nitf_Error_print(&error, stderr, "Error!"); + } + else if (test_main == (NITF_PLUGIN_TRE_HANDLER_FUNCTION)NULL) + { + printf("No such plugin could be found\n"); + } + else + { + int ok; + printf("Found DLL and main!!!\n"); + ok = (*test_main)(0, NULL, NULL, &error); + if (!ok) + { + nitf_Error_print(&error, stderr , ""); + } + + } + + + /* Don't need this now that the registry is a singleton + * if (! nitf_PluginRegistry_unload(reg, &error) ) + * { + * nitf_Error_print(&error, stdout, "Exiting..."); + * exit(EXIT_FAILURE); + * } + */ + + /* Don't need this now that the registry is a singleton + * + * nitf_PluginRegistry_destruct(®); + */ + return 0; + +} diff --git a/modules/c/nitf/tests/test_read_acftb.c b/modules/c/nitf/tests/test_read_acftb.c new file mode 100644 index 000000000..fef287296 --- /dev/null +++ b/modules/c/nitf/tests/test_read_acftb.c @@ -0,0 +1,180 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + + +void findInExtensions(nitf_Extensions* ext) +{ + /* These iterators are for going through the image segments */ + nitf_ListIterator iter; + nitf_ListIterator end; + nitf_List* list; + assert( ext ); + + list = nitf_Extensions_get(ext, "ACFTB"); + if (list) + { + /* Set the iterator to traverse the list of image segments */ + iter = nitf_List_begin(list); + /* And set this one to the end, so we'll know when we're done! */ + end = nitf_List_end(list); + + /* While we are not done... */ + while ( nitf_ListIterator_notEqualTo(&iter, &end) ) + { + nitf_TRE* tre; + + printf("Found ACFTB instance\n"); + + /* Get the image segment as its proper object */ + tre = (nitf_TRE*)nitf_ListIterator_get(&iter); + if ( nitf_HashTable_exists( tre->hash, "raw_data" ) ) + { + printf("Your plugin for ACFTB was not loaded so the data is contained in the RAW section\n"); + } + else + { + nitf_Pair* mission = nitf_HashTable_find( tre->hash, + "ACMSNID" ); + if (! mission ) + { + printf("Error: no Mission ID available\n"); + nitf_HashTable_print( tre->hash ); + + } + + + else + { + nitf_Field* field = (nitf_Field*)mission->data; + + printf("Mission ID: [%.*s]\n", field->length, field->raw); + } + } + + /* Increment the iterator so we can continue */ + nitf_ListIterator_increment(&iter); + } + } + else + { + printf("No ACFTB\n"); + } + +} + +int main(int argc, char **argv) +{ + + /* This is the error we hopefully wont receive */ + nitf_Error e; + + /* This is the reader */ + nitf_Reader* reader; + + /* This is the record of the file we are reading */ + nitf_Record* record; + + + /* This is the io handle we will give the reader to parse */ + nitf_IOHandle io; + + + /* These iterators are for going through the image segments */ + nitf_ListIterator iter; + nitf_ListIterator end; + + /* If you didnt give us a nitf file, we're croaking */ + if (argc != 2) + { + printf("Usage: %s \n", argv[0]); + exit(EXIT_FAILURE); + } + + + reader = nitf_Reader_construct(&e); + if (!reader) + { + nitf_Error_print(&e, stderr, "nitf::Reader::construct() failed"); + exit(EXIT_FAILURE); + } + + /* If you did, though, we'll be nice and open it for you */ + io = nitf_IOHandle_create(argv[1], + NITF_ACCESS_READONLY, + NITF_OPEN_EXISTING, + &e); + + /* But, oh boy, if you gave us a bad location...! */ + if ( NITF_INVALID_HANDLE( io ) ) + { + /* You had this coming! */ + nitf_Error_print(&e, stderr, "nitf::IOHandle::create() failed"); + exit(EXIT_FAILURE); + } + + /* Read the file */ + record = nitf_Reader_read(reader, + io, + &e); + if (!record) + { + nitf_Error_print(&e, stderr, "nitf::Reader::read() failed"); + exit(EXIT_FAILURE); + } + + /* Set the iterator to traverse the list of image segments */ + iter = nitf_List_begin(record->images); + /* And set this one to the end, so we'll know when we're done! */ + end = nitf_List_end(record->images); + + /* While we are not done... */ + while ( nitf_ListIterator_notEqualTo(&iter, &end) ) + { + + /* Get the image segment as its proper object */ + nitf_ImageSegment* imageSegment = + (nitf_ImageSegment*)nitf_ListIterator_get(&iter); + + assert( imageSegment->subheader); + if ( imageSegment->subheader->userDefinedSection ) + findInExtensions( imageSegment->subheader->userDefinedSection ); + else + printf("Nothing found in user defined section!\n"); + + if ( imageSegment->subheader->extendedSection ) + findInExtensions( imageSegment->subheader->extendedSection ); + else + printf("Nothing found in extended section!\n"); + + + /* Increment the iterator so we can continue */ + nitf_ListIterator_increment(&iter); + } + + nitf_Record_destruct(&record); + nitf_Reader_destruct(&reader); + nitf_IOHandle_close(io); + + return 0; +} diff --git a/modules/c/nitf/tests/test_record_clone.c b/modules/c/nitf/tests/test_record_clone.c new file mode 100644 index 000000000..5e62106a5 --- /dev/null +++ b/modules/c/nitf/tests/test_record_clone.c @@ -0,0 +1,94 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + +/* This test case just reads in a NITF file, clones it + * then destructs the clone and original. + * If you compile the library with the NITF_DEBUG flag set, + * then you can make sure there are no memory leaks. + * + * In the future, we should use the cloned record to test + * the functionality of a clone. + */ +int main(int argc, char **argv) +{ + /* Get the error object */ + nitf_Error error; + + /* This is the reader object */ + nitf_Reader* reader; + nitf_Record* record; + nitf_Record* cloneRecord; + + /* The IO handle */ + nitf_IOHandle io; + int num; + + /* Check argv and make sure we are happy */ + if ( argc != 2 ) + { + printf("Usage: %s \n", argv[0]); + exit(EXIT_FAILURE); + } + + io = nitf_IOHandle_create(argv[1], NITF_ACCESS_READONLY, NITF_OPEN_EXISTING, &error); + if ( NITF_INVALID_HANDLE( io ) ) + { + nitf_Error_print(&error, stdout, "Exiting..."); + exit( EXIT_FAILURE ); + } + + reader = nitf_Reader_construct(&error); + if (!reader) + { + nitf_Error_print(&error, stdout, "Exiting(1) ..."); + exit( EXIT_FAILURE ); + } + + /* read the record */ + record = nitf_Reader_read(reader, io, &error ); + if (!record) goto CATCH_ERROR; + + cloneRecord = nitf_Record_clone(record, &error); + if (!cloneRecord) + { + nitf_Error_print(&error, stdout, "Exiting(3) ..."); + exit( EXIT_FAILURE ); + } + + printf("Destructing Cloned Record\n"); + nitf_Record_destruct(&cloneRecord); + + nitf_IOHandle_close(io); + printf("Destructing Original Record\n"); + nitf_Record_destruct(&record); + + nitf_Reader_destruct(&reader); + + return 0; + +CATCH_ERROR: + printf("!!! we had a problem reading the file !!!\n"); + nitf_Error_print(&error, stdout, "Exiting..."); + exit(EXIT_FAILURE); +} diff --git a/modules/c/nitf/tests/test_replace_field.c b/modules/c/nitf/tests/test_replace_field.c new file mode 100644 index 000000000..34e75ff50 --- /dev/null +++ b/modules/c/nitf/tests/test_replace_field.c @@ -0,0 +1,189 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + +/* + * This test case does a search and replace for all field values that match. + * It tests the find functionality along with the replace for a node that + * already exists. This is not a good test case for determining full + * correctness of nitf_TRE_setField, since it doesnt try and create a + * new field. + * + */ + +void lookForTREField(nitf_Extensions* ext, + const char* tag, + const char* pattern, + const char* replace) +{ + nitf_ListIterator current, last; + + nitf_List* list = nitf_Extensions_getTREsByName(ext, tag); + if (list == NULL) return; + + current = nitf_List_begin(list); + last = nitf_List_end(list); + + while (nitf_ListIterator_notEqualTo(¤t, &last)) + { + nitf_Error error; + nitf_TRE* tre = nitf_ListIterator_get(¤t); + nitf_ListIterator currentInst; + nitf_ListIterator lastInst; + + nitf_List* found = nitf_TRE_find(tre, pattern, &error); + if (!found) return; + + + currentInst = nitf_List_begin(found); + lastInst = nitf_List_end(found); + + while (nitf_ListIterator_notEqualTo(¤tInst, &lastInst)) + { + nitf_Pair* pair = nitf_ListIterator_get(¤tInst); + nitf_Field* field = (nitf_Field*)pair->data; + printf("Found: %s [%.*s]\n", pair->key, (int)field->length, field->raw); + printf("Replacing with [%s]\n", replace); + if (!nitf_TRE_setField(tre, + pair->key, + (NITF_DATA*)replace, + strlen(replace), + &error)) + { + nitf_Error_print(&error, stdout, "Replace failed"); + return; + } + + field = nitf_TRE_getField(tre, pair->key); + printf("Round Trip Value: %s [%.*s]\n", pair->key, (int)field->length, field->raw); + nitf_ListIterator_increment(¤tInst); + + } + nitf_ListIterator_increment(¤t); + } + + +} + +int main(int argc, char **argv) +{ + /* Get the error object */ + nitf_Error error; + + /* so I can remember what Im doing with args */ + const char* treName; + const char* fieldName; + const char* replace; + /* This is the reader object */ + nitf_Reader *reader; + nitf_Record *record; + + /* The IO handle */ + nitf_IOHandle io; + int num; + + /* Check argv and make sure we are happy */ + if (argc != 5) + { + printf("Usage: %s \n", + argv[0]); + exit(EXIT_FAILURE); + } + + if (nitf_Reader_getNITFVersion(argv[1]) == NITF_VER_UNKNOWN) + { + printf("File: %s is not a NITF\n", argv[1]); + exit(EXIT_FAILURE); + } + + treName = argv[2]; + fieldName = argv[3]; + replace = argv[4]; + io = nitf_IOHandle_create(argv[1], NITF_ACCESS_READONLY, + NITF_OPEN_EXISTING, &error); + + if (NITF_INVALID_HANDLE(io)) + { + nitf_Error_print(&error, stdout, "Exiting..."); + exit(EXIT_FAILURE); + } + + reader = nitf_Reader_construct(&error); + if (!reader) + { + nitf_Error_print(&error, stdout, "Exiting (1) ..."); + exit(EXIT_FAILURE); + } + +#if NITF_VERBOSE_READER + printf("Here are the loaded handlers\n"); + printf("* * * * * * * * * * * * * * * *\n"); + nitf_HashTable_print(reader->reg->treHandlers); + printf("* * * * * * * * * * * * * * * *\n"); +#endif + record = nitf_Reader_read(reader, io, &error); + + + lookForTREField(record->header->extendedSection, treName, fieldName, replace); + lookForTREField(record->header->userDefinedSection, treName, fieldName, replace); + + if (!nitf_Field_get(record->header->numImages, + &num, NITF_CONV_INT, NITF_INT32_SZ, &error)) + goto CATCH_ERROR; + + /* And now show the image information */ + if (num > 0) + { + + /* Walk each image and show */ + nitf_ListIterator iter = nitf_List_begin(record->images); + nitf_ListIterator end = nitf_List_end(record->images); + + while (nitf_ListIterator_notEqualTo(&iter, &end)) + { + nitf_ImageSegment *segment = + (nitf_ImageSegment *) nitf_ListIterator_get(&iter); + + lookForTREField(segment->subheader->extendedSection, treName, fieldName, replace); + lookForTREField(segment->subheader->userDefinedSection, treName, fieldName, replace); + nitf_ListIterator_increment(&iter); + } + } + else + { + printf("No image in file!\n"); + } + + nitf_IOHandle_close(io); + nitf_Record_destruct(&record); + + nitf_Reader_destruct(&reader); + + return 0; + +CATCH_ERROR: + printf("!!! we had a problem reading the file !!!\n"); + nitf_Error_print(&error, stdout, "Exiting..."); + exit(EXIT_FAILURE); +} + diff --git a/modules/c/nitf/tests/test_setReal.c b/modules/c/nitf/tests/test_setReal.c new file mode 100644 index 000000000..686671f8d --- /dev/null +++ b/modules/c/nitf/tests/test_setReal.c @@ -0,0 +1,108 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +/* + Test program for testing set real field + + The optional argument is the length of the field +*/ + +#include + +void testField(nitf_Field *field, char *type, NITF_BOOL plus, + nitf_Uint32 length, double value); + +int main(int argc, char *argv[]) +{ + nitf_Field *field; /* Field for test */ + size_t length; /* Field length */ + nitf_Error errorObj; /* Error object */ + nitf_Error *error; /* Pointer to error object */ + + error = &errorObj; + + /* Note: + + NITF real fields are usually NITF_BCS_A because of the decimal place + or exponent + */ + + if (argc > 1) + length = atol(argv[1]); + else + length = 14; + + field = nitf_Field_construct(length, NITF_BCS_A, error); + if (field == NULL) + { + nitf_Error_print(error, stderr, "Could not create field\n"); + return(1); + } + + /* Test fields */ + + testField(field, "f", 1, length, 12.3456); + testField(field, "e", 1, length, 12.3456); + testField(field, "E", 1, length, 12.3456); + + testField(field, "f", 0, length, 12.3456); + testField(field, "e", 0, length, 12.3456); + testField(field, "E", 0, length, 12.3456); + + return(0); +} + +void testField(nitf_Field *field, char *type, NITF_BOOL plus, + nitf_Uint32 length, double value) +{ + NITF_BOOL ret; /* Return from function */ + nitf_Error errorObj; /* Error object */ + nitf_Error *error; /* Pointer to error object */ + nitf_Uint32 i; + + error = &errorObj; + + ret = nitf_Field_setReal(field, type, plus, value, error); + if (!ret) + { + nitf_Error_print(error, stderr, "Error setting field\n"); + return; + } + + + if (plus) + printf("Test of type %s with sign length = %d value = %lf\n", + type, length, value); + else + printf("Test of type %s without sign length = %d value = %lf\n", + type, length, value); + printf("||"); + for (i = 0;i < length;i++) printf("="); + printf("||\n||"); + nitf_Field_print(field); + printf("||\n"); + printf("||"); + for (i = 0;i < length;i++) printf("="); + printf("||\n"); + + return; +} diff --git a/modules/c/nitf/tests/test_text_read.c b/modules/c/nitf/tests/test_text_read.c new file mode 100644 index 000000000..48961318a --- /dev/null +++ b/modules/c/nitf/tests/test_text_read.c @@ -0,0 +1,150 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +/* + Test program for reading a Text segment + + This program reads a NITF file + + The calling sequence is: + + test_text_read inputFile + +*/ + +#include + +int main(int argc, char *argv[]) +{ + nitf_Reader *reader; /* Reader object */ + nitf_Record *record; /* Record used for input and output */ + nitf_IOHandle in; /* Input I/O handle */ + nitf_ListIterator iter; /* Iterator for getting the Texts */ + nitf_ListIterator end; /* Iterator marking the end of texts */ + nitf_TextSegment *text; /* Text segment to read */ + nitf_SegmentReader *textReader;/* Text reader object for reading data */ + char *data; /* Data buffer */ + int count; /* keeps track of iter count */ + static nitf_Error errorObj; /* Error object for messages */ + nitf_Error *error; /* Pointer to the error object */ + + error = &errorObj; + + if (argc != 2) + { + fprintf(stderr, "Usage %s inputFile\n", argv[0]); + exit(EXIT_FAILURE); + } + + /* Get the input record */ + + in = nitf_IOHandle_create(argv[1], + NITF_ACCESS_READONLY, NITF_OPEN_EXISTING, + error); + if (NITF_INVALID_HANDLE(in)) + { + nitf_Error_print(error, stderr, "Error opening input "); + exit(EXIT_FAILURE); + } + + reader = nitf_Reader_construct(error); + if (!reader) + { + nitf_IOHandle_close(in); + nitf_Error_print(error, stderr, "Error creating reader "); + exit(EXIT_FAILURE); + } + + record = nitf_Reader_read(reader, in, error); + if (!record) + { + nitf_Reader_destruct(&reader); + nitf_IOHandle_close(in); + nitf_Error_print(error, stderr, "Error reading input "); + exit(EXIT_FAILURE); + } + + count = 0; + iter = nitf_List_begin(record->texts); + end = nitf_List_end(record->texts); + while (nitf_ListIterator_notEqualTo(&iter, &end)) + { + text = (nitf_TextSegment *) nitf_ListIterator_get(&iter); + textReader = nitf_Reader_newTextReader(reader, count, error); + + if (!textReader) + { + nitf_Reader_destruct(&reader); + nitf_Record_destruct(&record); + nitf_IOHandle_close(in); + nitf_Error_print(error, stderr, "Could not create TextReader"); + exit(EXIT_FAILURE); + } + + fprintf(stdout, "Data length = %d\n", textReader->dataLength); + fprintf(stdout, "File offset = %llu\n", textReader->baseOffset); + fprintf(stdout, "Virtual offset = %llu\n", textReader->virtualOffset); + + data = (char *) NITF_MALLOC + (nitf_SegmentReader_getSize(textReader, error) + 1); + if (!data) + { + nitf_SegmentReader_destruct(&textReader); + nitf_Reader_destruct(&reader); + nitf_Record_destruct(&record); + nitf_IOHandle_close(in); + nitf_Error_print(error, stderr, "Could not allocate data buffer "); + exit(EXIT_FAILURE); + } + memset(data, 0, nitf_SegmentReader_getSize(textReader, error) + 1); + + + if (!nitf_SegmentReader_read + (textReader, data, textReader->dataLength, error)) + { + NITF_FREE(data); + nitf_SegmentReader_destruct(&textReader); + nitf_Reader_destruct(&reader); + nitf_Record_destruct(&record); + nitf_IOHandle_close(in); + nitf_Error_print(error, stderr, "Read failed "); + exit(EXIT_FAILURE); + } + + fprintf(stdout, "Data: |%s|\n", data); + + /* clean up */ + if (data) NITF_FREE(data); + if (textReader) nitf_SegmentReader_destruct(&textReader); + + + nitf_ListIterator_increment(&iter); + ++count; + } + + /* Clean-up */ + + nitf_Reader_destruct(&reader); + nitf_Record_destruct(&record); + nitf_IOHandle_close(in); + return 0; +} diff --git a/modules/c/nitf/tests/test_text_write.c b/modules/c/nitf/tests/test_text_write.c new file mode 100644 index 000000000..c53afb01f --- /dev/null +++ b/modules/c/nitf/tests/test_text_write.c @@ -0,0 +1,162 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include +#include + +#include + +/* ********************************************************************* +** This test creates a NITF from scratch with a single text segment. +** Its contents are passed in from the command line. +** ********************************************************************/ + +static const char* const DATE_TIME = "20120126000000"; + +static +NITF_BOOL initializeHeader(nitf_FileHeader* header, nitf_Error* error) +{ + return (nitf_Field_setString(header->fileHeader, "NITF", error) && + nitf_Field_setString(header->fileVersion, "02.10", error) && + nitf_Field_setUint32(header->complianceLevel, 3, error) && + nitf_Field_setString(header->systemType, "BF01", error) && + nitf_Field_setString(header->originStationID, "SF.net", error) && + nitf_Field_setString(header->fileDateTime, DATE_TIME, error) && + nitf_Field_setString(header->fileTitle, "Text Segment Test", error) && + nitf_Field_setString(header->classification, "U", error) && + nitf_Field_setUint32(header->encrypted, 0, error)); +} + +static +NITF_BOOL initializeTextSubheader(nitf_TextSubheader* header, + nitf_Error* error) +{ + return (nitf_Field_setString(header->dateTime, DATE_TIME, error) && + nitf_Field_setString(header->title, "Text Segment Test", error)); +} + +int main(int argc, char** argv) +{ + const char* outText = NULL; + const char* outPathname = NULL; + nitf_IOHandle outIO = NRT_INVALID_HANDLE_VALUE; + nitf_Writer* writer = NULL; + nitf_TextSegment* textSegment = NULL; + nitf_SegmentWriter* textWriter = NULL; + nitf_SegmentSource* textSource = NULL; + nitf_Record* record = NULL; + nitf_Error error; + + error.level = NRT_NO_ERR; + + /* Parse the command line */ + if (argc != 3) + { + fprintf(stderr, "Usage: %s \n", argv[0]); + return 1; + } + outText = argv[1]; + outPathname = argv[2]; + + /* Do the work */ + outIO = nitf_IOHandle_create(outPathname, + NITF_ACCESS_WRITEONLY, + NITF_CREATE, + &error); + + if (NITF_INVALID_HANDLE(outIO)) + { + goto CATCH_ERROR; + } + + writer = nitf_Writer_construct(&error); + if (!writer) + { + goto CATCH_ERROR; + } + + record = nitf_Record_construct(NITF_VER_21, &error); + if (!record) + { + goto CATCH_ERROR; + } + + if (!initializeHeader(record->header, &error)) + { + goto CATCH_ERROR; + } + + textSegment = nitf_Record_newTextSegment(record, &error); + if (!textSegment) + { + fprintf(stderr, "new text segment failed\n"); + return 1; + } + if (!initializeTextSubheader(textSegment->subheader, &error)) + { + goto CATCH_ERROR; + } + + if (!nitf_Writer_prepare(writer, record, outIO, &error)) + { + goto CATCH_ERROR; + } + + textWriter = nitf_Writer_newTextWriter(writer, 0, &error); + if (!textWriter) + { + goto CATCH_ERROR; + } + + textSource = nitf_SegmentMemorySource_construct(outText, + strlen(outText), + 0, 0, 0, &error); + if (!textSource) + { + goto CATCH_ERROR; + } + + if (!nitf_SegmentWriter_attachSource(textWriter, textSource, &error)) + { + goto CATCH_ERROR; + } + + nitf_Writer_write(writer, &error); + +CATCH_ERROR: + if (!NITF_INVALID_HANDLE(outIO)) + { + nitf_IOHandle_close(outIO); + } + if (writer) + { + nitf_Writer_destruct(&writer); + } + + if (error.level != NRT_NO_ERR) + { + nitf_Error_print(&error, stderr, "Exiting..."); + return 1; + } + + return 0; +} diff --git a/modules/c/nitf/tests/test_tre_mods.c b/modules/c/nitf/tests/test_tre_mods.c new file mode 100644 index 000000000..c74a82b41 --- /dev/null +++ b/modules/c/nitf/tests/test_tre_mods.c @@ -0,0 +1,318 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + + +int showTRE(nitf_TRE* tre) +{ + nitf_Error error; + int i = 0; + nitf_Uint32 treLength; + nitf_TREEnumerator* it; + + treLength = tre->handler->getCurrentSize(tre, &error); + + printf("\n--------------- %s TRE (%d) ---------------\n", + tre->tag, treLength); + + it = nitf_TRE_begin(tre, &error); + while(it && it->hasNext(&it)) + { + nitf_Pair* fieldPair = it->next(it, &error); + i++; + if (fieldPair) + { + printf("%s = [", fieldPair->key); + nitf_Field_print((nitf_Field *) fieldPair->data); + printf("]\n"); + } + else + { + printf("ERROR, no field found!\n"); + } + } + return 1; +} + +NITF_BOOL testNestedMod(nitf_Error* error) +{ + NITF_BOOL exists; + nitf_TRE* tre = nitf_TRE_construct("ACCHZB", NULL, error); + if (!tre) + { + return NITF_FAILURE; + } + exists = nitf_TRE_setField(tre, "NUMACHZ", "01", 2, error); + printf("Set ok? %s\n", exists ? "OK" : "FAIL"); + exists = nitf_TRE_setField(tre, "UNIAAH[0]", "abc", 3, error); + printf("Set ok? %s\n", exists ? "OK" : "FAIL"); + exists = nitf_TRE_setField(tre, "AAH[0]", "00000", 5, error); + printf("Set ok? %s\n", exists ? "OK" : "FAIL"); + exists = nitf_TRE_setField(tre, "UNIAPH[0]", "def", 3, error); + printf("Set ok? %s\n", exists ? "OK" : "FAIL"); + exists = nitf_TRE_setField(tre, "APH[0]", "00000", 5, error); + printf("Set ok? %s\n", exists ? "OK" : "FAIL"); + exists = nitf_TRE_setField(tre, "NUMPTS[0]", "001", 3, error); + printf("Set ok? %s\n", exists ? "OK" : "FAIL"); + exists = + nitf_TRE_setField(tre, "LON[0][0]", "000000000000000", 15, error); + printf("Set ok? %s\n", exists ? "OK" : "FAIL"); + exists = + nitf_TRE_setField(tre, "LAT[0][0]", "000000000000000", 15, error); + printf("Set ok? %s\n", exists ? "OK" : "FAIL"); + + /* print the TRE. should print the value now */ + showTRE(tre); + + /* destruct the TREs */ + nitf_TRE_destruct(&tre); +return NITF_SUCCESS; +} + +NITF_BOOL testIncompleteCondMod(nitf_Error* error) +{ + NITF_BOOL exists; + nitf_TRE* tre = nitf_TRE_construct("ACCPOB", NULL, error); + if (!tre) + { + return NITF_FAILURE; + } + printf("Before Mods\n"); + showTRE(tre); + printf("\n\n"); + + exists = nitf_TRE_setField(tre, "NUMACPO", "01", 2, error); + if (!exists) + { + return NITF_FAILURE; + } + + printf("Again\n"); + showTRE(tre); + printf("\n\n"); + + exists = nitf_TRE_setField(tre, "UNIAAH[0]", "FT0", 3, error); + if (!exists) + { + return NITF_FAILURE; + } + + exists = nitf_TRE_setField(tre, "NUMPTS[0]", "002", 3, error); + if (!exists) + { + return NITF_FAILURE; + } + + + /* print the TRE. should print the value now */ + printf("After Mods\n"); + showTRE(tre); + + + /* destruct the TREs */ + nitf_TRE_destruct(&tre); + return NITF_SUCCESS; + +} + +NITF_BOOL testClone(nitf_Error* error) +{ + + NITF_BOOL exists; + nitf_TRE *dolly; /* used for clone */ + nitf_TRE* tre = nitf_TRE_construct("JITCID", NULL, error); + if (!tre) + { + return NITF_FAILURE; + } + exists = nitf_TRE_setField(tre, "FILCMT", "fyi", 3, error); + printf("Set ok? %s\n", exists ? "yes" : "no"); + + /* print the TRE. should print the value now */ + showTRE(tre); + + /* now, clone it */ + dolly = nitf_TRE_clone(tre, error); + if (!dolly) + { + return NITF_FAILURE; + } + printf("About to print the cloned TRE\n"); + showTRE(dolly); + + /* destruct the TREs */ + nitf_TRE_destruct(&tre); + nitf_TRE_destruct(&dolly); + return NITF_SUCCESS; +} + +NITF_BOOL testBasicMod(nitf_Error* error) +{ + /* construct a tre */ + NITF_BOOL exists; + nitf_TRE *tre = nitf_TRE_construct("ACFTA", "ACFTA_132", error); + if (!tre) + { + return NITF_FAILURE; + } + + /* print the TRE -- should print fields, but all blank */ + showTRE(tre); + + /* set a value. make sure it went ok */ + printf("Now, set the value of 'AC_MSN_ID' to 'fly-by'. Set ok? "); + exists = nitf_TRE_setField(tre, "AC_MSN_ID", "fly-by", 6, error); + printf("%s\n", exists ? "OK" : "FAIL"); + + printf("Now, print the TRE:\n----------\n"); + /* print the TRE. should print the value now */ + showTRE(tre); + printf("----------\n"); + + /* re-set the same value. make sure it went ok */ + printf("Now, re-set the value of 'AC_MSN_ID' to 'sky-photo'. Set ok? "); + exists = nitf_TRE_setField(tre, "AC_MSN_ID", "sky-photo", 9, error); + printf("%s\n", exists ? "OK" : "FAIL"); + + printf("Now, print the TRE:\n----------\n"); + /* print the TRE. should print the value now */ + showTRE(tre); + printf("----------\n"); + + /* make sure that we can't set an invalid tag */ + printf("Try to set an invalid tag. Can we? "); + exists = nitf_TRE_setField(tre, "invalid-tag", "sky-photo", 9, error); + printf("%s\n", exists ? "Yes. FAIL" : "No. GOOD!"); + + printf("Now, print the TRE:\n----------\n"); + /* print the TRE. should print the value now */ + showTRE(tre); + printf("----------\n"); + + /* destruct the TRE */ + nitf_TRE_destruct(&tre); + + return NITF_SUCCESS; +} + +NITF_BOOL testSize(nitf_Error* error) +{ + nitf_TRE* tre = nitf_TRE_construct("AIMIDB", NULL, error); + int treLength; + + if (!tre) + { + nitf_Error_print(error, stdout, "Exiting..."); + return NITF_FAILURE; + } + + treLength = tre->handler->getCurrentSize(tre, error); + + printf("Computed TRE Length = %d\n", treLength); + + /* destruct the TRE */ + nitf_TRE_destruct(&tre); + return NITF_SUCCESS; +} + +/* This test should be used to verify the TRE modifications work. + * It probably should not be added to a core canon of tests, but + * it is useful to test any changes with the TRE API + */ +int main(int argc, char **argv) +{ + /* Get the error object */ + nitf_Error error; + + if (!testClone(&error)) + { + nitf_Error_print(&error, stdout, "Exiting..."); + exit(EXIT_FAILURE); + } + + if (!testSize(&error)) + { + nitf_Error_print(&error, stdout, "Exiting..."); + exit(EXIT_FAILURE); + + } + + if (!testBasicMod(&error)) + { + nitf_Error_print(&error, stdout, "Exiting..."); + exit(EXIT_FAILURE); + + } + + if (!testNestedMod(&error)) + { + nitf_Error_print(&error, stdout, "Exiting..."); + exit(EXIT_FAILURE); + + } + + if (!testIncompleteCondMod(&error)) + { + nitf_Error_print(&error, stdout, "Exiting..."); + exit(EXIT_FAILURE); + + } + + + /* TODO: this *is* important, but in order to continue + other test, I need to block it out for now */ + + /* now, let's try to construct based on a description set + { + nitf_TREDescriptionInfo *infoPtr = NULL; + nitf_TREDescriptionSet *descriptions = + nitf_TRE_getDescriptionSet("ACFTA", &error); + int numDescriptions = 0; + infoPtr = descriptions->descriptions; + while (infoPtr && (infoPtr->description != NULL)) + { + numDescriptions++; + infoPtr++; + } + printf("Found %d descriptions for ACFTA\n", numDescriptions); + + infoPtr = descriptions->descriptions; + while (infoPtr && (infoPtr->description != NULL)) + { + printf("Name: %s, Length: %d\n--------------------------------\n", + infoPtr->name, infoPtr->lengthMatch); + tre = nitf_TRE_construct("ACFTA", NULL, &error); + if (!tre) + { + nitf_Error_print(&error, stdout, "Exiting..."); + exit(EXIT_FAILURE); + } + nitf_TRE_print(tre, &error); + infoPtr++; + nitf_TRE_destruct(&tre); + printf("--------------------------------\n"); + } + }*/ + + return 0; +} diff --git a/modules/c/nitf/tests/test_writer_3.c b/modules/c/nitf/tests/test_writer_3.c new file mode 100644 index 000000000..bf411da30 --- /dev/null +++ b/modules/c/nitf/tests/test_writer_3.c @@ -0,0 +1,864 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + + +/* ********************************************************************* +** This test tests the round-trip process of taking an input NITF +** file and writing it to a new file. This includes writing the image +** segments (headers, extensions, and image data). This is an example +** of how users can write the image data to their NITF file +** ********************************************************************/ + +nitf_Record *doRead(const char *inFile); + +#define SHOW(X) printf("%s=[%s]\n", #X, X) +#define SHOWI(X) printf("%s=[%ld]\n", #X, X) +#define SHOWLL(X) printf("%s=[%lld]\n", #X, X) +#define SHOW_VAL(X) printf("%s=[%.*s]\n", #X, ((X==0)?8:((X->raw==0)?5:(int)X->length)), ((X==0)?"(nulptr)":((X->raw==0)?"(nul)":X->raw))) + +#define GET_UINT32(FIELD, DATA_PTR, ERROR) \ + success = nitf_Field_get(FIELD, DATA_PTR, NITF_CONV_UINT, NITF_INT32_SZ, ERROR); \ + if (!success) goto CATCH_ERROR; + +#define GET_UINT64(FIELD, DATA_PTR, ERROR) \ + success = nitf_Field_get(FIELD, DATA_PTR, NITF_CONV_UINT, NITF_INT64_SZ, ERROR); \ + if (!success) goto CATCH_ERROR; + +/* pass in a negative number for bandNum if you don't want a band in the name */ +char *makeBandName(const char *rootFile, const char* segment, int segmentNum, int bandNum) +{ + char *file = (char *) NITF_MALLOC(NITF_MAX_PATH); + int pos; + + /* find end slash */ + for (pos = strlen(rootFile) - 1; + pos && rootFile[pos] != '\\' && rootFile[pos] != '/'; pos--); + + if (bandNum >= 0) + NITF_SNPRINTF(file, NITF_MAX_PATH, + "%s__%s_%d_band_%d", &rootFile[pos + 1], + segment, segmentNum, bandNum); + else + NITF_SNPRINTF(file, NITF_MAX_PATH, "%s__%s_%d", &rootFile[pos + 1], + segment, segmentNum); + /* remove decimals */ + for (pos = strlen(file) - 1; pos; pos--) + { + if (file[pos] == '.') + { + file[pos] = '_'; + } + } + strcat(file, ".man"); + printf("File: %s\n", file); + return file; +} + +void freeBandName(char **rootFile) +{ + if (*rootFile) + { + NITF_FREE(*rootFile); + *rootFile = NULL; + + } +} +void showFileHeader(nitf_FileHeader * header) +{ + unsigned int i; + nitf_Uint32 num; + nitf_Error error; + nitf_Uint32 len; + nitf_Uint64 dataLen; + NITF_BOOL success; + + SHOW_VAL(header->fileHeader); + SHOW_VAL(header->fileVersion); + SHOW_VAL(header->complianceLevel); + SHOW_VAL(header->systemType); + SHOW_VAL(header->originStationID); + SHOW_VAL(header->fileDateTime); + SHOW_VAL(header->fileTitle); + SHOW_VAL(header->classification); + SHOW_VAL(header->messageCopyNum); + SHOW_VAL(header->messageNumCopies); + SHOW_VAL(header->encrypted); + SHOW_VAL(header->backgroundColor); + SHOW_VAL(header->originatorName); + SHOW_VAL(header->originatorPhone); + + SHOW_VAL(header->fileLength); + SHOW_VAL(header->headerLength); + + /* Attention: If the classification is U, the security group */ + /* section should be empty! For that reason, we wont print */ + /* The security group for now */ + + SHOW_VAL(header->securityGroup->classificationSystem); + SHOW_VAL(header->securityGroup->codewords); + SHOW_VAL(header->securityGroup->controlAndHandling); + SHOW_VAL(header->securityGroup->releasingInstructions); + SHOW_VAL(header->securityGroup->declassificationType); + SHOW_VAL(header->securityGroup->declassificationDate); + SHOW_VAL(header->securityGroup->declassificationExemption); + SHOW_VAL(header->securityGroup->downgrade); + SHOW_VAL(header->securityGroup->downgradeDateTime); + SHOW_VAL(header->securityGroup->classificationText); + SHOW_VAL(header->securityGroup->classificationAuthorityType); + SHOW_VAL(header->securityGroup->classificationAuthority); + SHOW_VAL(header->securityGroup->classificationReason); + SHOW_VAL(header->securityGroup->securitySourceDate); + SHOW_VAL(header->securityGroup->securityControlNumber); + + GET_UINT32(header->numImages, &num, &error); + printf("The number of IMAGES contained in this file [%ld]\n", (long)num); + for (i = 0; i < num; i++) + { + GET_UINT32(header->imageInfo[i]->lengthSubheader, &len, &error); + GET_UINT64(header->imageInfo[i]->lengthData, &dataLen, &error); + printf("\tThe length of IMAGE subheader [%d]: %ld bytes\n", + i, (long)len); + printf("\tThe length of the IMAGE data: %llu bytes\n\n", dataLen); + } + + return; + +CATCH_ERROR: + printf("Error processing\n"); +} + +nitf_ImageSource *setupBands(int nbands, int imageNum, + const char *inRootFile) +{ + nitf_Error error; + int i; + nitf_BandSource *bandSource; + nitf_ImageSource *iSource = nitf_ImageSource_construct(&error); + if (!iSource) + goto CATCH_ERROR; + for (i = 0; i < nbands; i++) + { + char *inFile = makeBandName(inRootFile, "img", imageNum, i); + + nitf_IOHandle sourceHandle = + nitf_IOHandle_create(inFile, NITF_ACCESS_READONLY, + NITF_OPEN_EXISTING, &error); + if (NITF_INVALID_HANDLE(sourceHandle)) + goto CATCH_ERROR; + + freeBandName(&inFile); + + bandSource = nitf_FileSource_construct(sourceHandle, + 0, 0 /*gets ignored */ , 0, + &error); + freeBandName(&inFile); + + if (!bandSource) + { + goto CATCH_ERROR; + } + if (!nitf_ImageSource_addBand(iSource, bandSource, &error)) + { + goto CATCH_ERROR; + } + } + return iSource; + +CATCH_ERROR: + nitf_Error_print(&error, stderr, "While constructing image source"); + exit(EXIT_FAILURE); +} + +void doWrite(nitf_Record * record, char *inRootFile, char *outFile) +{ + nitf_ListIterator iter; + + nitf_ImageWriter *iWriter; + nitf_ImageSource *iSource; + + nitf_SegmentWriter *segmentWriter; + nitf_SegmentSource *segmentSource; + + nitf_ListIterator end; + int i; + int numImages; + int numTexts; + int numDataExtensions; + nitf_Writer *writer = NULL; + nitf_Error error; + nitf_IOHandle output_io = nitf_IOHandle_create(outFile, + NITF_ACCESS_WRITEONLY, + NITF_CREATE, + &error); + + if (NITF_INVALID_HANDLE(output_io)) + { + goto CATCH_ERROR; + } + + writer = nitf_Writer_construct(&error); + if (!writer) + { + goto CATCH_ERROR; + } + if (!nitf_Writer_prepare(writer, record, output_io, &error)) + { + goto CATCH_ERROR; + } + + if (!nitf_Field_get + (record->header->numImages, &numImages, NITF_CONV_INT, + NITF_INT32_SZ, &error)) + { + nitf_Error_print(&error, stderr, "nitf::Value::get() failed"); + numImages = 0; + } + + if (!nitf_Field_get + (record->header->numTexts, &numTexts, NITF_CONV_INT, + NITF_INT32_SZ, &error)) + { + nitf_Error_print(&error, stderr, "nitf::Value::get() failed"); + numTexts = 0; + } + + if (!nitf_Field_get + (record->header->numDataExtensions, &numDataExtensions, NITF_CONV_INT, + NITF_INT32_SZ, &error)) + { + nitf_Error_print(&error, stderr, "nitf::Value::get() failed"); + numDataExtensions = 0; + } + + if (record->images) + { + end = nitf_List_end(record->images); + for (i = 0; i < numImages; i++) + { + int nbands; + nitf_ImageSegment *imseg = NULL; + iter = nitf_List_at(record->images, i); + assert(nitf_ListIterator_notEqualTo(&iter, &end)); + + imseg = (nitf_ImageSegment *) nitf_ListIterator_get(&iter); + assert(imseg); + + if (!nitf_Field_get + (imseg->subheader->numImageBands, &nbands, NITF_CONV_INT, + NITF_INT32_SZ, &error)) + goto CATCH_ERROR; + + iWriter = nitf_Writer_newImageWriter(writer, i, NULL, &error); + if (!iWriter) + { + goto CATCH_ERROR; + } + iSource = setupBands(nbands, i, inRootFile); + if (!iSource) + goto CATCH_ERROR; + if (!nitf_ImageWriter_attachSource(iWriter, iSource, &error)) + goto CATCH_ERROR; + } + } + + if (record->texts) + { + end = nitf_List_end(record->texts); + for (i = 0; i < numTexts; i++) + { + nitf_TextSegment *textSeg = NULL; + char *inFile = NULL; + nitf_IOHandle sourceHandle; + + iter = nitf_List_at(record->texts, i); + assert(nitf_ListIterator_notEqualTo(&iter, &end)); + + textSeg = (nitf_TextSegment *) nitf_ListIterator_get(&iter); + assert(textSeg); + + segmentWriter = nitf_Writer_newTextWriter(writer, i, &error); + if (!segmentWriter) + { + goto CATCH_ERROR; + } + + /* setup file */ + inFile = makeBandName(inRootFile, "text", i, -1); + sourceHandle = + nitf_IOHandle_create(inFile, NITF_ACCESS_READONLY, + NITF_OPEN_EXISTING, &error); + if (NITF_INVALID_HANDLE(sourceHandle)) + goto CATCH_ERROR; + + freeBandName(&inFile); + + segmentSource = nitf_SegmentFileSource_construct(sourceHandle, 0, 0, &error); + if (!segmentSource) + goto CATCH_ERROR; + if (!nitf_SegmentWriter_attachSource(segmentWriter, segmentSource, &error)) + goto CATCH_ERROR; + } + } + + if (record->dataExtensions) + { + end = nitf_List_end(record->dataExtensions); + for (i = 0; i < numDataExtensions; i++) + { + nitf_DESegment *DESeg = NULL; + char *inFile = NULL; + nitf_IOHandle sourceHandle; + + iter = nitf_List_at(record->dataExtensions, i); + assert(nitf_ListIterator_notEqualTo(&iter, &end)); + + DESeg = (nitf_DESegment *) nitf_ListIterator_get(&iter); + assert(DESeg); + + segmentWriter = nitf_Writer_newDEWriter(writer, i, &error); + if (!segmentWriter) + { + goto CATCH_ERROR; + } + + /* setup file */ + inFile = makeBandName(inRootFile, "DE", i, -1); + sourceHandle = + nitf_IOHandle_create(inFile, NITF_ACCESS_READONLY, + NITF_OPEN_EXISTING, &error); + if (NITF_INVALID_HANDLE(sourceHandle)) + goto CATCH_ERROR; + + freeBandName(&inFile); + + segmentSource = nitf_SegmentFileSource_construct(sourceHandle, 0, 0, &error); + if (!segmentSource) + goto CATCH_ERROR; + if (!nitf_SegmentWriter_attachSource(segmentWriter, segmentSource, &error)) + goto CATCH_ERROR; + + } + } + + if (!nitf_Writer_write(writer, &error)) + { + goto CATCH_ERROR; + } + + + /*nitf_ImageSource_destruct(&iSource);*/ + nitf_IOHandle_close(output_io); + nitf_Writer_destruct(&writer); + return; +CATCH_ERROR: + nitf_Error_print(&error, stderr, "During write"); + exit(EXIT_FAILURE); +} + +int main(int argc, char **argv) +{ + + nitf_Record *record = NULL; /* a record object */ +#if 0 + nitf_ListIterator iter; /* current pos iterator */ + nitf_ListIterator end; /* end of list iterator */ + nitf_ImageSegment *segment = NULL; /* the image segment */ + + NITF_BOOL success; /* status bool */ + + nitf_IOHandle input_io; /* input IOHandle */ + nitf_IOHandle output_io; /* output IOHandle */ +#endif + + /* Check argv and make sure we are happy */ + if (argc != 3) + { + printf("Usage: %s \n", argv[0]); + exit(EXIT_FAILURE); + } + record = doRead(argv[1]); + + showFileHeader(record->header); + doWrite(record, argv[1], argv[2]); + nitf_Record_destruct(&record); + + return 0; +} + +/* this writes the text data from a text segment to a file */ +void writeTextData(nitf_TextSegment * segment, + const char *fileName, + nitf_SegmentReader * reader, + int textNumber, nitf_Error * error) +{ + + size_t toRead; + char * buf = NULL; + char * outName = NULL; + + nitf_IOHandle file; + + toRead = (size_t)(segment->end - segment->offset); + + buf = (char*)NITF_MALLOC(toRead + 1); + if (!buf) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + return; + } + + /* get the data */ + if (nitf_SegmentReader_read(reader, buf, toRead, error) != NITF_SUCCESS) + { + /* TODO populate error */ + goto CATCH_ERROR; + } + + outName = makeBandName(fileName, "text", textNumber, -1); + file = nitf_IOHandle_create(outName, NITF_ACCESS_WRITEONLY, + NITF_CREATE, error); + freeBandName(&outName); + + if (NITF_INVALID_HANDLE(file)) + { + goto CATCH_ERROR; + } + if (!nitf_IOHandle_write(file, (const char*)buf, toRead, error)) + goto CATCH_ERROR; + nitf_IOHandle_close(file); + +CATCH_ERROR: + if (buf) NITF_FREE(buf); + return; +} + +/*XXX */ +/* this writes the data extension data from a data segment to a file */ +void writeDEData(nitf_DESegment * segment, + const char *fileName, + nitf_SegmentReader * reader, + int DENumber, nitf_Error * error) +{ + +#define DE_READ_SIZE 16*1024 + + /*XXX + size_t toRead = DE_READ_SIZE; + size_t leftToRead; + size_t amtToRead; + */ + nitf_Uint64 toRead = DE_READ_SIZE; + nitf_Uint64 leftToRead; + nitf_Uint64 amtToRead; + char * buf = NULL; + char * outName = NULL; + + nitf_IOHandle file; + + leftToRead = (size_t)(segment->end - segment->offset); + fprintf(stderr, "XXX Data Ext write %llu %llu %llu\n", leftToRead, segment->end , segment->offset); + + buf = (char*)NITF_MALLOC(toRead + 1); + if (!buf) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + return; + } + fprintf(stderr, "XXX Data Ext A\n"); + + /* Make file output file anme and create */ + outName = makeBandName(fileName, "DE", DENumber, -1); + fprintf(stderr, "XXX Data Ext names %s %s\n", fileName, outName); + file = nitf_IOHandle_create(outName, NITF_ACCESS_WRITEONLY, + NITF_CREATE, error); + freeBandName(&outName); + fprintf(stderr, "XXX Data Ext B\n"); + + if (NITF_INVALID_HANDLE(file)) + { + goto CATCH_ERROR; + } + + /* get the data and write to file */ + while (leftToRead > 0) + { + fprintf(stderr, "XXX Data Ext C\n"); + amtToRead = DE_READ_SIZE; + if (amtToRead > leftToRead) + amtToRead = leftToRead; + fprintf(stderr, "XXX Data Ext C2 %llu\n", amtToRead); + if (nitf_SegmentReader_read(reader, buf, (size_t)amtToRead, error) != NITF_SUCCESS) + { + /* TODO populate error */ + goto CATCH_ERROR; + } + + fprintf(stderr, "XXX Data Ext D %llu\n", amtToRead); + if (!nitf_IOHandle_write(file, (const char*)buf, (size_t)amtToRead, error)) + goto CATCH_ERROR; + fprintf(stderr, "XXX Data Ext E\n"); + + leftToRead -= amtToRead; + } + nitf_IOHandle_close(file); + +CATCH_ERROR: + if (buf) NITF_FREE(buf); + return; +} + +void manuallyWriteImageBands(nitf_ImageSegment * segment, + const char *imageName, + nitf_ImageReader * deserializer, + int imageNumber, nitf_Error * error) +{ + char *file; + nitf_Uint32 nBits, nBands, xBands, nRows, nColumns; + size_t subimageSize; + nitf_SubWindow *subimage; + unsigned int i; + int padded; + nitf_Uint8 **buffer = NULL; + nitf_Uint32 band; + nitf_Uint32 *bandList = NULL; + + NITF_TRY_GET_UINT32(segment->subheader->numBitsPerPixel, &nBits, + error); + NITF_TRY_GET_UINT32(segment->subheader->numImageBands, &nBands, error); + NITF_TRY_GET_UINT32(segment->subheader->numMultispectralImageBands, + &xBands, error); + nBands += xBands; + NITF_TRY_GET_UINT32(segment->subheader->numRows, &nRows, error); + NITF_TRY_GET_UINT32(segment->subheader->numCols, &nColumns, error); + subimageSize = nRows * nColumns * NITF_NBPP_TO_BYTES(nBits); + + printf("Image number: %d\n", imageNumber); + printf("NBANDS -> %d\n" + "XBANDS -> %d\n" + "NROWS -> %d\n" + "NCOLS -> %d\n" + "PVTYPE -> %.*s\n" + "NBPP -> %.*s\n" + "ABPP -> %.*s\n" + "PJUST -> %.*s\n" + "IMODE -> %.*s\n" + "NBPR -> %.*s\n" + "NBPC -> %.*s\n" + "NPPBH -> %.*s\n" + "NPPBV -> %.*s\n" + "IC -> %.*s\n" + "COMRAT -> %.*s\n", + nBands, + xBands, + nRows, + nColumns, + (int)segment->subheader->pixelValueType->length, + segment->subheader->pixelValueType->raw, + (int)segment->subheader->numBitsPerPixel->length, + segment->subheader->numBitsPerPixel->raw, + (int)segment->subheader->actualBitsPerPixel->length, + segment->subheader->actualBitsPerPixel->raw, + (int)segment->subheader->pixelJustification->length, + segment->subheader->pixelJustification->raw, + (int)segment->subheader->imageMode->length, + segment->subheader->imageMode->raw, + (int)segment->subheader->numBlocksPerRow->length, + segment->subheader->numBlocksPerRow->raw, + (int)segment->subheader->numBlocksPerCol->length, + segment->subheader->numBlocksPerCol->raw, + (int)segment->subheader->numPixelsPerHorizBlock->length, + segment->subheader->numPixelsPerHorizBlock->raw, + (int)segment->subheader->numPixelsPerVertBlock->length, + segment->subheader->numPixelsPerVertBlock->raw, + (int)segment->subheader->imageCompression->length, + segment->subheader->imageCompression->raw, + (int)segment->subheader->compressionRate->length, + segment->subheader->compressionRate->raw); + + + buffer = (nitf_Uint8 **) malloc(sizeof(nitf_Uint8*) * nBands); + band = 0; + bandList = (nitf_Uint32 *) malloc(sizeof(nitf_Uint32 *) * nBands); + + subimage = nitf_SubWindow_construct(error); + assert(subimage); + + subimage->startCol = 0; + subimage->startRow = 0; + subimage->numRows = nRows; + subimage->numCols = nColumns; + + for (band = 0; band < nBands; band++) + bandList[band] = band; + subimage->bandList = bandList; + subimage->numBands = nBands; + + assert(buffer); + for (i = 0; i < nBands; i++) + { + buffer[i] = (nitf_Uint8 *) malloc(subimageSize); + assert(buffer[i]); + } + /* This should change to returning failures! */ + /* + if (! nitf_ImageIO_read(segment->imageIO, io, &subimage, buffer, &padded, + error) ) + { + nitf_Error_print(error, stderr, "Read failed"); + goto CATCH_ERROR; + } + */ + if (!nitf_ImageReader_read + (deserializer, subimage, buffer, &padded, error)) + { + nitf_Error_print(error, stderr, "Read failed"); + goto CATCH_ERROR; + } + for (i = 0; i < nBands; i++) + { + + nitf_IOHandle toFile; + file = makeBandName(imageName, "img", imageNumber, i); + toFile = nitf_IOHandle_create(file, NITF_ACCESS_WRITEONLY, + NITF_CREATE, error); + freeBandName(&file); + if (NITF_INVALID_HANDLE(toFile)) + { + goto CATCH_ERROR; + + } + if (!nitf_IOHandle_write(toFile, + (const char *) buffer[i], + subimageSize, error)) + + { + goto CATCH_ERROR; + } + nitf_IOHandle_close(toFile); + } + + /* free buffers */ + for (i = 0; i < nBands; i++) + { + free(buffer[i]); + } + free(buffer); + free(bandList); + nitf_SubWindow_destruct(&subimage); + return; + +CATCH_ERROR: + /* free buffers */ + for (i = 0; i < nBands; i++) + { + free(buffer[i]); + } + free(buffer); + free(bandList); + nitf_Error_print(error, stderr, "Manual write failed"); + + +} +nitf_Record *doRead(const char *inFile) +{ + /* This is the error we hopefully wont receive */ + nitf_Error e; + + /* This is the reader */ + nitf_Reader *reader; + + /* This is the record of the file we are reading */ + nitf_Record *record; + + /* This is the io handle we will give the reader to parse */ + nitf_IOHandle io; + + int count = 0; + int numImages; + int numTexts; + int numDataExtensions; + + nitf_ListIterator iter; + nitf_ListIterator end; + + + nitf_ImageSegment *imageSegment = NULL; + nitf_ImageReader *deserializer = NULL; + nitf_TextSegment *textSegment = NULL; + nitf_DESegment *deSegment = NULL; + nitf_SegmentReader *segmentReader = NULL; + nitf_SegmentReader *deReader = NULL; + + reader = nitf_Reader_construct(&e); + if (!reader) + { + nitf_Error_print(&e, stderr, "nitf::Reader::construct() failed"); + exit(EXIT_FAILURE); + } + + /* If you did, though, we'll be nice and open it for you */ + io = nitf_IOHandle_create(inFile, + NITF_ACCESS_READONLY, + NITF_OPEN_EXISTING, &e); + + /* But, oh boy, if you gave us a bad location...! */ + if (NITF_INVALID_HANDLE(io)) + { + /* You had this coming! */ + nitf_Error_print(&e, stderr, "nitf::IOHandle::create() failed"); + exit(EXIT_FAILURE); + } + + /* Read the file */ + record = nitf_Reader_read(reader, io, &e); + if (!record) + { + nitf_Error_print(&e, stderr, "nitf::Reader::read() failed"); + exit(EXIT_FAILURE); + } + + if (!nitf_Field_get + (record->header->numImages, &numImages, NITF_CONV_INT, + NITF_INT32_SZ, &e)) + { + nitf_Error_print(&e, stderr, "nitf::Field::get() failed"); + numImages = 0; + } + + if (!nitf_Field_get + (record->header->numTexts, &numTexts, NITF_CONV_INT, + NITF_INT32_SZ, &e)) + { + nitf_Error_print(&e, stderr, "nitf::Field::get() failed"); + numTexts = 0; + } + + if (!nitf_Field_get + (record->header->numDataExtensions, &numDataExtensions, NITF_CONV_INT, + NITF_INT32_SZ, &e)) + { + nitf_Error_print(&e, stderr, "nitf::Field::get() failed"); + numDataExtensions = 0; + } + + if (record->images) + { + end = nitf_List_end(record->images); + + for (count = 0; count < numImages; ++count) + { + iter = nitf_List_at(record->images, count); + if (nitf_ListIterator_equals(&iter, &end)) + { + printf("Out of bounds on iterator [%d]!\n", count); + exit(EXIT_FAILURE); + } + imageSegment = (nitf_ImageSegment *) nitf_ListIterator_get(&iter); + deserializer = nitf_Reader_newImageReader(reader, count, NULL, &e); + if (!deserializer) + { + nitf_Error_print(&e, stderr, "Couldnt spawn deserializer"); + exit(EXIT_FAILURE); + } + printf("Writing image %d... ", count); + /* Write the thing out */ + manuallyWriteImageBands(imageSegment, inFile, deserializer, count, + &e); + + nitf_ImageReader_destruct(&deserializer); + + printf("done.\n"); + /* Increment the iterator so we can continue */ + nitf_ListIterator_increment(&iter); + } + } + + + /* loop over texts and read the data to a file */ + if (record->texts) + { + end = nitf_List_end(record->texts); + + for (count = 0; count < numTexts; ++count) + { + iter = nitf_List_at(record->texts, count); + if (nitf_ListIterator_equals(&iter, &end)) + { + printf("Out of bounds on iterator [%d]!\n", count); + exit(EXIT_FAILURE); + } + textSegment = (nitf_TextSegment *) nitf_ListIterator_get(&iter); + segmentReader = nitf_Reader_newTextReader(reader, count, &e); + if (!segmentReader) + { + nitf_Error_print(&e, stderr, "Couldnt spawn deserializer"); + exit(EXIT_FAILURE); + } + printf("Writing text %d... ", count); + /* Write the thing out */ + writeTextData(textSegment, inFile, segmentReader, count, &e); + nitf_SegmentReader_destruct(&segmentReader); + + /* Increment the iterator so we can continue */ + nitf_ListIterator_increment(&iter); + } + } + + /*XXX*/ + /* loop over data extensions and read the data to a file */ + if (record->dataExtensions) + { + fprintf(stderr, "XXX Data Ext %d\n", numDataExtensions); + end = nitf_List_end(record->dataExtensions); + + for (count = 0; count < numDataExtensions; ++count) + { + iter = nitf_List_at(record->dataExtensions, count); + if (nitf_ListIterator_equals(&iter, &end)) + { + printf("Out of bounds on iterator [%d]!\n", count); + exit(EXIT_FAILURE); + } + deSegment = (nitf_DESegment *) nitf_ListIterator_get(&iter); + deReader = nitf_Reader_newDEReader(reader, count, &e); + if (!deReader) + { + nitf_Error_print(&e, stderr, "Couldnt spawn deserializer"); + exit(EXIT_FAILURE); + } + printf("Writing data extension %d... ", count); + /* Write the thing out */ + writeDEData(deSegment, inFile, deReader, count, &e); + nitf_SegmentReader_destruct(&segmentReader); + + /* Increment the iterator so we can continue */ + nitf_ListIterator_increment(&iter); + } + } + nitf_Reader_destruct(&reader); + return record; + +} diff --git a/modules/c/nitf/tests/test_writer_s.c b/modules/c/nitf/tests/test_writer_s.c new file mode 100644 index 000000000..630067a5f --- /dev/null +++ b/modules/c/nitf/tests/test_writer_s.c @@ -0,0 +1,447 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include + + +/* ********************************************************************* +** This test tests the round-trip process of taking an input NITF +** file and writing it to a new file. This includes writing the image +** segments (headers, extensions, and image data). This is an example +** of how users can write the image data to their NITF file +** +** This version uses a nitf_ImageSource (memory version) to supply the +** data to the writer (The memory buffers are filled using nitf_ImageIO_read) +** +** ********************************************************************/ + + +#define SHOW(X) printf("%s=[%s]\n", #X, X) +#define SHOWI(X) printf("%s=[%ld]\n", #X, X) +#define SHOWLL(X) printf("%s=[%lld]\n", #X, X) +#define SHOW_VAL(X) printf("%s=[%.*s]\n", #X, ((X==0)?8:((X->raw==0)?5:X->length)), ((X==0)?"(nulptr)":((X->raw==0)?"(nul)":X->raw))) + +#define GET_UINT32(FIELD, DATA_PTR, ERROR) \ + success = nitf_Field_get(FIELD, DATA_PTR, NITF_CONV_UINT, NITF_INT32_SZ, ERROR); \ + if (!success) goto CATCH_ERROR; + +#define GET_UINT64(FIELD, DATA_PTR, ERROR) \ + success = nitf_Field_get(FIELD, DATA_PTR, NITF_CONV_UINT, NITF_INT64_SZ, ERROR); \ + if (!success) goto CATCH_ERROR; + +void showFileHeader(nitf_FileHeader* header) +{ + unsigned int i; + nitf_Uint32 num; + nitf_Error error; + nitf_Uint32 len; + nitf_Uint64 dataLen; + NITF_BOOL success; + + SHOW_VAL(header->fileHeader); + SHOW_VAL(header->fileVersion); + SHOW_VAL(header->complianceLevel); + SHOW_VAL(header->systemType); + SHOW_VAL(header->originStationID); + SHOW_VAL(header->fileDateTime); + SHOW_VAL(header->fileTitle); + SHOW_VAL(header->classification); + SHOW_VAL(header->messageCopyNum); + SHOW_VAL(header->messageNumCopies); + SHOW_VAL(header->encrypted); + SHOW_VAL(header->backgroundColor); + SHOW_VAL(header->originatorName); + SHOW_VAL(header->originatorPhone); + + SHOW_VAL(header->fileLength); + SHOW_VAL(header->headerLength); + + /* Attention: If the classification is U, the security group */ + /* section should be empty! For that reason, we wont print */ + /* The security group for now */ + + SHOW_VAL(header->securityGroup->classificationSystem); + SHOW_VAL(header->securityGroup->codewords); + SHOW_VAL(header->securityGroup->controlAndHandling); + SHOW_VAL(header->securityGroup->releasingInstructions); + SHOW_VAL(header->securityGroup->declassificationType); + SHOW_VAL(header->securityGroup->declassificationDate); + SHOW_VAL(header->securityGroup->declassificationExemption); + SHOW_VAL(header->securityGroup->downgrade); + SHOW_VAL(header->securityGroup->downgradeDateTime); + SHOW_VAL(header->securityGroup->classificationText); + SHOW_VAL(header->securityGroup->classificationAuthorityType); + SHOW_VAL(header->securityGroup->classificationAuthority); + SHOW_VAL(header->securityGroup->classificationReason); + SHOW_VAL(header->securityGroup->securitySourceDate); + SHOW_VAL(header->securityGroup->securityControlNumber); + + GET_UINT32(header->numImages, &num, &error); + printf("The number of IMAGES contained in this file [%ld]\n", num); + for (i = 0; i < num; i++) + { + GET_UINT32(header->imageInfo[i]->lengthSubheader, &len, &error); + GET_UINT64(header->imageInfo[i]->lengthData, &dataLen, &error); + printf("\tThe length of IMAGE subheader [%d]: %ld bytes\n", + i, len); + printf("\tThe length of the IMAGE data: %lld bytes\n\n", + dataLen); + } + + return; + +CATCH_ERROR: + printf("Error processing\n"); +} + +int doWrite(nitf_ImageSegment* segment, nitf_ImageSource *imgSrc, + nitf_IOHandle output_io, nitf_ImageIO* ioClone); + +NITF_BOOL writeImage(nitf_ImageSegment* segment, nitf_IOHandle input_io, nitf_IOHandle output_io) +{ + nitf_Error error; + nitf_Off offset; + int ret; + + nitf_ImageIO* ioClone; + + nitf_Uint8** buffer; + nitf_Uint32 nBits, nBands, xBands, nRows, nColumns; + nitf_SubWindow *subimage; + size_t subimageSize; + nitf_Uint32 band; + nitf_Uint32 *bandList; + NITF_BOOL success; + int padded; + + nitf_ImageSource *imgSrc; /* Image source object */ + nitf_BandSource *bandSrc; /* Current band source object */ + + + /* clone the imageIO */ + ioClone = nitf_ImageIO_clone(segment->imageIO, &error); + if (!ioClone) + { + nitf_Error_print(&error, stderr, "Clone failed"); + goto CATCH_ERROR; + } + + /* get IO offset, and set the offset for the ImageIO */ + offset = nitf_IOHandle_tell(output_io, &error); + if (!NITF_IO_SUCCESS(offset)) goto CATCH_ERROR; + + if (!nitf_ImageIO_setFileOffset(segment->imageIO, offset, &error)) + { + goto CATCH_ERROR; + } + + /* Read image */ + + GET_UINT32(segment->subheader->numBitsPerPixel, &nBits, &error); + GET_UINT32(segment->subheader->numImageBands, &nBands, &error); + GET_UINT32(segment->subheader->numMultispectralImageBands, &xBands, &error); + nBands += xBands; + GET_UINT32(segment->subheader->numRows, &nRows, &error); + GET_UINT32(segment->subheader->numCols, &nColumns, &error); + subimageSize = nRows * nColumns * NITF_NBPP_TO_BYTES(nBits); + + + /* Allcoate buffers */ + buffer = (nitf_Uint8 **)malloc(8 * nBands); + assert(buffer); + + for (band = 0; band < nBands; band++) + { + buffer[band] = (nitf_Uint8*)malloc(subimageSize); + assert(buffer[band]); + } + + /* Set-up band array and subimage */ + + bandList = (nitf_Uint32 *)malloc(sizeof(nitf_Uint32 *) * nBands); + + subimage = nitf_SubWindow_construct(&error); + assert(subimage); + + subimage->startCol = 0; + subimage->startRow = 0; + subimage->numRows = nRows; + subimage->numCols = nColumns; + + for (band = 0; band < nBands; band++) + { + bandList[band] = band; + } + subimage->bandList = bandList; + subimage->numBands = nBands; + + /* Read data */ + + if (!nitf_ImageIO_read(ioClone, + input_io, subimage, buffer, &padded, &error) ) + { + nitf_Error_print(&error, stderr, "Read failed"); + return(0); + } + free(bandList); + + /* Setup for image source */ + + imgSrc = nitf_ImageSource_construct(&error); + if (imgSrc == NULL) + return(0); + for (band = 0; band < nBands; band++) + { + bandSrc = nitf_MemorySource_construct(buffer[band], (size_t) subimageSize, + (nitf_Off) 0, NITF_NBPP_TO_BYTES(nBits), 0, &error); + if (bandSrc == NULL) + return(0); + + if (!nitf_ImageSource_addBand(imgSrc, bandSrc, &error)) + return(0); + } + + /* Do write */ + + ret = doWrite(segment, imgSrc, output_io, ioClone); + + if (ioClone) nitf_ImageIO_destruct(&ioClone); + nitf_ImageSource_destruct(&imgSrc); + + /* OK return */ + return ret; + +CATCH_ERROR: + if (ioClone) nitf_ImageIO_destruct(&ioClone); + printf("ERROR processing\n"); + return 0; +} + +/*==========*/ + +int doWrite(nitf_ImageSegment* segment, nitf_ImageSource *imgSrc, + nitf_IOHandle output_io, nitf_ImageIO* ioClone) +{ + nitf_Error error; + nitf_Uint8** user; + nitf_Uint32 nBits, nBands, xBands, nRows, nColumns, row; + size_t rowSize; + int band; + NITF_BOOL success; /* Used in GET macros */ + nitf_BandSource *bandSrc; /* Current band source object */ + nitf_ImageSource *imgSrcTmp; + GET_UINT32(segment->subheader->numBitsPerPixel, &nBits, &error); + GET_UINT32(segment->subheader->numImageBands, &nBands, &error); + GET_UINT32(segment->subheader->numMultispectralImageBands, &xBands, &error); + nBands += xBands; + GET_UINT32(segment->subheader->numRows, &nRows, &error); + GET_UINT32(segment->subheader->numCols, &nColumns, &error); + rowSize = nColumns * NITF_NBPP_TO_BYTES(nBits); + + + + /* Allocate buffers */ + + user = (nitf_Uint8 **)malloc(8 * nBands); + assert(user); + for (band = 0; band < nBands; band++) + { + user[band] = (nitf_Uint8*)malloc(rowSize); + assert(user[band]); + } + + + /* setup for write */ + nitf_ImageIO_writeSequential(segment->imageIO, output_io, &error); + + /* loop over the rows */ + for (row = 0; row < nRows; ++row) + { + imgSrcTmp = imgSrc; + /* set the band pointer */ + for (band = 0; band < nBands; ++band) + { + bandSrc = nitf_ImageSource_getBand(imgSrcTmp, band, &error); + if (bandSrc == NULL) + return(0); + + (*(bandSrc->iface->read))(bandSrc->data, (char*)user[band], + (size_t) rowSize, &error); + } + + /* write the row */ + if (!nitf_ImageIO_writeRows(segment->imageIO, output_io, 1, user, &error)) + { + return(0); + } + } + + /* done writing */ + if (!nitf_ImageIO_writeDone(segment->imageIO, output_io, &error)) + { + return(0); + } + + free(user); + + return(1); +CATCH_ERROR: + return(0); /* Needed for the GET macros */ +} + +/*==========*/ + +int main(int argc, char **argv) +{ + nitf_Reader* reader; /* The reader object */ + nitf_Writer* writer; /* The writer object */ + nitf_Record* record; /* a record object */ + nitf_Record* record2; + nitf_ListIterator iter; /* current pos iterator */ + nitf_ListIterator end; /* end of list iterator */ + nitf_ImageSegment* segment; /* the image segment */ + + NITF_BOOL success; /* status bool */ + + nitf_IOHandle input_io; /* input IOHandle */ + nitf_IOHandle output_io; /* output IOHandle */ + nitf_Error error; /* error object */ + + /* Check argv and make sure we are happy */ + if (argc != 3) + { + printf("Usage: %s \n", argv[0]); + exit(EXIT_FAILURE); + } + + input_io = nitf_IOHandle_create(argv[1], + NITF_ACCESS_READONLY, + NITF_OPEN_EXISTING, &error); + if ( NITF_INVALID_HANDLE(input_io)) + { + goto CATCH_ERROR; + } + + output_io = nitf_IOHandle_create(argv[2], + NITF_ACCESS_WRITEONLY, + NITF_CREATE | NITF_TRUNCATE, + &error); + + if ( NITF_INVALID_HANDLE(output_io)) + { + goto CATCH_ERROR; + } + + reader = nitf_Reader_construct(&error); + if (!reader) + { + goto CATCH_ERROR; + } + + writer = nitf_Writer_construct(&error); + if (!writer) + { + goto CATCH_ERROR; + } + + record = nitf_Record_construct(&error); + if (!record) + { + goto CATCH_ERROR; + } + + assert(nitf_Reader_read(reader, input_io, record, &error)); + showFileHeader(record->header); + + /* Write to the file */ + success = nitf_Writer_writeHeader(writer, record->header, output_io, &error); + if (!success) goto CATCH_ERROR; + + + /* ------ IMAGES ------ */ + iter = nitf_List_begin(record->images); + end = nitf_List_end(record->images); + while (nitf_ListIterator_notEqualTo(&iter, &end)) + { + /* Cast it to an imageSegment... */ + segment = (nitf_ImageSegment*)nitf_ListIterator_get(&iter); + + /* write the image subheader */ + if (!nitf_Writer_writeImageSubheader(writer, + segment->subheader, + record->header->NITF_FVER->raw, + output_io, + &error)) + { + goto CATCH_ERROR; + } + + /* Now, write the image */ + if (!writeImage(segment, input_io, output_io)) + { + goto CATCH_ERROR; + } + + nitf_ListIterator_increment(&iter); + } + + nitf_IOHandle_close(input_io); + nitf_IOHandle_close(output_io); + nitf_Record_destruct(&record); + nitf_Writer_destruct(&writer); + + /* Open the file we just wrote to, and dump it to screen */ + input_io = nitf_IOHandle_create(argv[2], + NITF_ACCESS_READONLY, + NITF_OPEN_EXISTING, + &error); + if (NITF_INVALID_HANDLE(input_io)) + { + goto CATCH_ERROR; + } + + record2 = nitf_Record_construct(&error); + if (!record2) + { + goto CATCH_ERROR; + } + + assert(nitf_Reader_readHeader(reader, input_io, record2, &error)); + showFileHeader(record2->header); + + nitf_IOHandle_close(input_io); + nitf_Record_destruct(&record2); + nitf_Reader_destruct(&reader); + + return 0; + +CATCH_ERROR: + if (input_io) nitf_IOHandle_close(input_io); + if (output_io) nitf_IOHandle_close(output_io); + if (record2) nitf_Record_destruct(&record2); + if (reader) nitf_Reader_destruct(&reader); + if (record) nitf_Record_destruct(&record); + if (writer) nitf_Writer_destruct(&writer); + nitf_Error_print(&error, stdout, "Exiting..."); + exit(EXIT_FAILURE); +} + diff --git a/modules/c/nitf/tests/verify/mem_sane.pl b/modules/c/nitf/tests/verify/mem_sane.pl new file mode 100755 index 000000000..5983bfad6 --- /dev/null +++ b/modules/c/nitf/tests/verify/mem_sane.pl @@ -0,0 +1,80 @@ +#!/usr/bin/perl -w + +#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# +#_____M____E____M_______S____A____N____E____.____P____L____# +# This program will check a memory trace from a nitf # +# library run. The nitf library must have been compiled # +# with NITF_DEBUG defined, otherwise no memory trace can # +# be generated. # +# # +# The usage for the program is quite simple. After you # +# do a run, the program will dump out a file named # +# memory_trace. or something along those lines. # +# You should run this program with that trace as an arg. # +# # +# (perl) mem_sane.pl # +#__________________________________________________________# + +# Make sure the args are right +@ARGV == 1 or die "Usage $0 "; + +# The name of the trace +my $mem = $ARGV[0]; + +# A hash of info about how the memory was allocated +# The key is the address which was malloc'ed +my %mem_info; + +# Open the trace or die +open MEM, $mem or die "Could not open memory trace \"$mem\""; + +# Scan the trace... +while () { + + # Here is where we allocated + if (/^\tMALLOC\t(\S+)\t([0-9]+)\t(\S+)\t([0-9]+)/) { + $mem_info{$1}[0] = $2; + $mem_info{$1}[1] = $3; + $mem_info{$1}[2] = $4; + } + # Check if there is a corresponding deletion + elsif (/^REQUEST: free\t\[(\S+)\]/) { + + # If it doesnt exist, usually that just means that NITF_MALLOC wasnt + # used to malloc it, but NITF_FREE was + # that is usually not a problem + if ( ! exists $mem_info{$1} ) + { + print "Warning: Deleting unknown memory at $1\n"; + print "\t(This could be the result of a hash adopting which is OK)\n"; + my $questionable = ; + if ($questionable =~ /\tFREE\t(\S+)\t([0-9]+)/) + { + print "\tThe questionable free was performed in file \"$1\" at line $2\n"; + } + else + { + print "Warning: got out of sync. This is a bug. Sorry\n"; + } + print "\n"; + } + # If there IS a corresponding free, delete this from the hash + # of unresolved values + else + { + delete $mem_info{$1}; + } + } + +} +# Print all of the leftover unfreed values +foreach my $loc ( keys %mem_info ) { + my $size = $mem_info{ $loc }[0]; + my $file = $mem_info{ $loc }[1]; + my $line = $mem_info{ $loc }[2]; + print "Unfreed: [$loc]\n"; + print "\tNumber of bytes [$size]\n"; + print "\tAllocated in file \"$file\" at line [$line]\n\n"; +} + +close MEM; diff --git a/modules/c/nitf/unittests/Test.h b/modules/c/nitf/unittests/Test.h new file mode 100644 index 000000000..2334a2e2f --- /dev/null +++ b/modules/c/nitf/unittests/Test.h @@ -0,0 +1,84 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __TEST_H__ +#define __TEST_H__ + +#ifdef __cplusplus + +#include +#include + +#define CHECK(X) X(std::string(#X)); std::cout << #X << ": PASSED" << std::endl +#define TEST_ASSERT(X) if (!(X)) { die_printf("%s (%s,%s,%d): FAILED: Value should not be NULL\n", testName.c_str(), __FILE__, __FUNC__, __LINE__) } +#define TEST_ASSERT_NULL(X) if ((X) != NULL) { die_printf("%s (%s,%s,%d): FAILED: Value should be NULL\n", testName.c_str(), __FILE__, __FUNC__, __LINE__) } +#define TEST_ASSERT_EQ(X1, X2) if ((X1) != (X2)) { die_printf("%s (%s,%s,%d): FAILED: Recv'd %s, Expected %s\n", testName.c_str(), __FILE__, __FUNC__, __LINE__, str::toString(X1).c_str(), str::toString(X2).c_str()) } +#define TEST_ASSERT_ALMOST_EQ(X1, X2) if (fabs((X1) - (X2)) > std::numeric_limits::epsilon()) { die_printf("%s (%s,%s,%d): FAILED: Recv'd %s, Expected %s\n", testName.c_str(), __FILE__, __FUNC__, __LINE__, str::toString(X1).c_str(), str::toString(X2).c_str()) } +#define TEST_CASE(X) void X(std::string testName) + +#else + +# include +# include +# include + +/* Negotiate the 'context' */ +#define TEST_FILE __FILE__ +#define TEST_LINE __LINE__ +#if defined(__GNUC__) +# define TEST_FUNC __PRETTY_FUNCTION__ +#elif __STDC_VERSION__ < 199901 +# define TEST_FUNC "unknown function" +#else /* Should be c99 */ +# define TEST_FUNC __func__ +#endif + +#define CHECK(X) X(#X); fprintf(stderr, "%s : PASSED\n", #X); +#define CHECK_ARGS(X) X(#X,argc,argv); fprintf(stderr, "%s : PASSED\n", #X); +#define TEST_ASSERT(X) if (!(X)) { \ + fprintf(stderr, "%s (%s,%s,%d) : FAILED: Value should not be NULL\n", testName, TEST_FILE, TEST_FUNC, TEST_LINE); \ + exit(EXIT_FAILURE); \ +} +#define TEST_ASSERT_NULL(X) if ((X) != NULL) { \ + fprintf(stderr, "%s (%s,%s,%d) : FAILED: Value should be NULL\n", testName, TEST_FILE, TEST_FUNC, TEST_LINE); \ + exit(EXIT_FAILURE); \ +} +#define TEST_ASSERT_EQ_STR(X1, X2) if (strcmp((X1), (X2)) != 0) { \ + fprintf(stderr, "%s (%s,%s,%d) : FAILED: Recv'd %s, Expected %s\n", testName, TEST_FILE, TEST_FUNC, TEST_LINE, X1, X2); \ + exit(EXIT_FAILURE); \ +} +#define TEST_ASSERT_EQ_INT(X1, X2) if ((X1) != (X2)) { \ + fprintf(stderr, "%s (%s,%s,%d) : FAILED: Recv'd %d, Expected %d\n", testName, TEST_FILE, TEST_FUNC, TEST_LINE, (int)X1, (int)X2); \ + exit(EXIT_FAILURE); \ +} +/* TODO use epsilon for comparing floating points */ +#define TEST_ASSERT_EQ_FLOAT(X1, X2) if (fabs((X1) - (X2)) > .0000001f) { \ + fprintf(stderr, "%s (%s,%s,%d) : FAILED: Recv'd %f, Expected %f\n", testName, TEST_FILE, TEST_FUNC, TEST_LINE, X1, X2); \ + exit(EXIT_FAILURE); \ +} + +#define TEST_CASE(X) void X(const char* testName) +#define TEST_CASE_ARGS(X) void X(const char* testName, int argc, char **argv) + +#endif + +#endif diff --git a/modules/c/nitf/unittests/test_create.c b/modules/c/nitf/unittests/test_create.c new file mode 100644 index 000000000..0137c3d79 --- /dev/null +++ b/modules/c/nitf/unittests/test_create.c @@ -0,0 +1,41 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include +#include "Test.h" + +TEST_CASE(testCreate) +{ + nitf_IOHandle handle; + nitf_Error error; + + handle = nitf_IOHandle_create("test_create.ntf", NITF_ACCESS_READONLY, NITF_CREATE, &error); + TEST_ASSERT(!NITF_INVALID_HANDLE(handle)); + + nitf_IOHandle_close(handle); +} + +int main(int argc, char **argv) +{ + CHECK(testCreate); + return 0; +} diff --git a/modules/c/nitf/unittests/test_create_nitf.c b/modules/c/nitf/unittests/test_create_nitf.c new file mode 100644 index 000000000..7aeb000b3 --- /dev/null +++ b/modules/c/nitf/unittests/test_create_nitf.c @@ -0,0 +1,1253 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + + +/** + * This test serves as an example to show how one can construct and write + * a NITF from scratch. + */ + + +#include +#include "Test.h" + + +static const struct { + unsigned int width; + unsigned int height; + unsigned int bytesPerPixel; + unsigned char data[188 * 36 * 3 + 1]; +} NITRO_IMAGE = { + 188, 36, 3, + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\376\376\376\375\375\375\376\376\376\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\375\375\375" + "\373\373\373\372\372\372\373\373\373\375\375\375\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\337\256\256" + "\325\227\227\323\222\222\323\221\221\322\220\220\322\220\220\322\220\220" + "\322\220\220\322\220\220\322\220\220\322\220\220\323\220\220\322\217\217" + "\321\215\215\320\213\213\343\273\273\374\374\374\371\371\371\370\370\370" + "\372\372\372\376\376\376\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\337\256\256\325\227\227" + "\323\222\222\323\221\221\322\220\220\323\220\220\322\217\217\321\214\214" + "\316\210\210\322\226\226\361\361\361\355\355\355\362\362\362\371\371\371" + "\376\376\376\377\377\377\377\377\377\354\320\320\327\233\233\325\226\226" + "\323\222\222\323\221\221\322\220\220\322\220\220\323\220\220\323\220\220" + "\323\220\220\323\222\222\333\246\246\377\377\377\333\245\245\323\222\222" + "\323\221\221\323\221\221\322\220\220\322\220\220\322\220\220\322\220\220" + "\322\220\220\322\220\220\322\220\220\322\220\220\322\220\220\322\220\220" + "\322\220\220\322\220\220\322\220\220\322\220\220\322\220\220\322\220\220" + "\322\220\220\322\220\220\322\220\220\322\220\220\322\220\220\322\220\220" + "\322\220\220\322\220\220\322\220\220\322\220\220\322\220\220\322\220\220" + "\322\220\220\322\217\217\321\216\216\321\220\220\362\347\347\353\333\334" + "\224q\202\224q\202\223q\202\223q\202\222p\201\222p\201\222p\201\222p\201" + "\222p\201\222p\201\222p\201\222p\201\222p\201\222p\201\222p\201\222p\201" + "\222p\201\222p\201\222p\201\222p\201\222p\201\222p\201\222p\201\222p\201" + "\240~\215\316\307\320\336\336\345\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\355\355\361\305" + "\305\321\223\223\251ll\212GGlGGl\20\20?\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3" + "\0\0""3\37\37KAAhUUw\215\215\244\300\300\314\365\365\367\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\365\346\346\231" + "\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231" + "\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\236\16\16\367\367\367\362\362" + "\362\361\361\361\364\364\364\372\372\372\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\371\360\360\231\0\0" + "\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\275kk\333" + "\333\333\333\333\333\346\346\346\364\364\364\375\375\375\377\377\377\377" + "\377\377\240\23\23\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0" + "\0\231\0\0\231\0\0\231\0\0\310||\357\334\334\231\0\0\231\0\0\231\0\0\231" + "\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231" + "\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231" + "\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231" + "\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\355\350\350\233/4\231\0\0\231" + "\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231" + "\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231" + "\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\31\0+\0\0""3\0\0""3QQt\312\312" + "\325\376\376\376\375\375\375\375\375\375\375\375\375\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\370\370\371\270\270\306[[|\21\21@\0\0""3\0\0""3\0\0""3\0" + "\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0" + """3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3--W\232\232\256\364\364\366\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\316\206\206\231\0\0\231\0\0\231\0\0\231\0\0" + "\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0" + "\231\0\0\231\0\0\231\0\0\332\257\257\352\352\352\347\347\347\353\353\353" + "\364\364\364\375\375\375\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\326\230\230\231\0\0\231\0\0\231\0\0\231\0\0\231" + "\0\0\231\0\0\231\0\0\231\0\0\231\0\0\305\262\262\300\300\300\310\310\310" + "\336\336\336\363\363\363\375\375\375\377\377\377\353\315\315\231\0\0\231" + "\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231" + "\0\0\341\315\315\307zz\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231" + "\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231" + "\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231" + "\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231" + "\0\0\231\0\0\262NN\340\330\330\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231" + "\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231" + "\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231" + "\0\0\231\0\0\211\0\5\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3^^~\372\372\372\371" + "\371\371\372\372\372\375\375\375\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\331\331\340]]}\0\0""3\0\0""3\0\0""3\0\0" + """3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3" + "\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0" + "\0""3\16\16>\205\205\235\377\377\377\376\376\376\375\375\375\374\374\374" + "\374\374\374\375\375\375\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\246!!\231\0\0\231\0\0\231" + "\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231" + "\0\0\231\0\0\231\0\0\231\0\0\231\0\0\264JJ\343\343\343\336\336\336\342\342" + "\342\355\355\355\370\370\370\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\246!!\231\0\0\231\0\0\231\0\0\231\0\0\231\0" + "\0\231\0\0\231\0\0\231\0\0\240\32\32\255\255\255\250\250\250\275\275\275" + "\335\335\335\364\364\364\376\376\376\377\377\377\306qq\231\0\0\231\0\0\231" + "\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\241\33\33\316" + "\316\316\243\36\36\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0" + "\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0" + "\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0" + "\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0" + "\0\231\0\0\302\225\225\277\222\225\231\0\0\231\0\0\231\0\0\231\0\0\231\0" + "\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0" + "\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0" + "\0\231\0\0\231\0\0W\0\26\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3~~\226" + "\363\363\363\365\365\365\373\373\373\376\376\376\377\377\377\377\377\377" + "\377\377\377\333\333\342$$P\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0" + """3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3" + "\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0" + "\0""3\0\0""3++U\360\360\362\371\371\371\366\366\366\365\365\365\370\370\370" + "\374\374\374\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\364\343\343\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0" + "\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0" + "\231\0\0\231\0\0\231\0\0\335\326\326\327\327\327\331\331\331\344\344\344" + "\362\362\362\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\364\343\343\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231" + "\0\0\231\0\0\253__\231\231\231\236\236\236\275\275\275\341\341\341\367\367" + "\367\376\376\376\377\377\377\240\21\21\231\0\0\231\0\0\231\0\0\231\0\0\231" + "\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\254aa\263\242\242\231\0\0\231" + "\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231" + "\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231" + "\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231" + "\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\312\305\305" + "\2253:\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231" + "\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231" + "\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\"\0(\0\0""3" + "\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\33\33I\347\347\347\355\355\355\370\370" + "\370\375\375\375\377\377\377\371\371\372``\200\0\0""3\0\0""3\0\0""3\0\0""3" + "\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0" + "\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0" + """3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3**U\351\351\353\356\356" + "\356\354\354\354\357\357\357\366\366\366\376\376\376\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\315\202\202\231\0\0\231\0\0\231" + "\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231" + "\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\305\210\210\325\325" + "\325\323\323\323\335\335\335\355\355\355\374\374\374\377\377\377\377\377" + "\377\377\377\377\377\377\377\315\202\202\231\0\0\231\0\0\231\0\0\231\0\0" + "\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\244\223\223\217\217\217\236\236" + "\236\304\304\304\351\351\351\372\372\372\377\377\377\351\310\310\231\0\0" + "\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0" + "\231\0\0\233\213\213\231\203\203\244hh\252kk\256mm\260nn\263pp\263pp\265" + "qq\267ss\272vv\277yy\305||\265KK\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0" + "\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\234\15\15\246hh\244gg\247ii\253" + "kk\256mm\260nn\262oo\263pp\263pp\264qq\266rr\266ss\277\222\222\323\323\323" + "\223\2\4\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0" + "\231\0\0v\0\14\214\26\34\227!#\227!#\230\"$\231#%\232$&\233%'\234&(\221\32" + "\40\212\24\33y\3\16v\0\14v\0\14v\0\14v\0\14\0\0""3\0\0""3\0\0""3\0\0""3\0" + "\0""3\0\0""3\0\0""3\0\0""3\333\333\333\346\346\346\366\366\366\374\374\374" + "\333\333\342\22\22A\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0" + """3\0\0""3\0\0""3\0\0""3\32\32F^^w\224\224\235\247\247\253\270\270\270\275" + "\275\275\303\303\303\312\312\312\252\252\264\206\206\23299`\0\0""3\0\0""3" + "\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3||" + "\225\345\345\345\337\337\337\342\342\342\354\354\354\370\370\370\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\246!!\231\0\0\231\0" + "\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\242\33\33\231\0\0\231" + "\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\247))\325\325" + "\325\320\320\320\327\327\327\347\347\347\367\367\367\376\376\376\377\377" + "\377\377\377\377\377\377\377\246!!\231\0\0\231\0\0\231\0\0\231\0\0\231\0" + "\0\231\0\0\231\0\0\231\0\0\237\32\32\225\225\225\214\214\214\246\246\246" + "\320\320\320\357\357\357\375\375\375\377\377\377\305nn\231\0\0\231\0\0\231" + "\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\235\32\32\177" + "\177\177sss{{{\211\211\211\226\226\226\240\240\240\250\250\250\257\257\257" + "\265\265\265\277\277\277\315\315\315\336\336\336\355\355\355\276__\231\0" + "\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0" + "\0\242NN{{{ttt\200\200\200\214\214\214\230\230\230\241\241\241\247\247\247" + "\253\253\253\257\257\257\270\270\270\303\303\303\317\317\317\330\330\330" + "\304\242\245\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231" + "\0\0\231\0\0v\0\14\0\0""3\217\217\222\202\202\202\202\202\202\216\216\216" + "\231\231\231\245\245\245\261\261\261\277\277\277\317\317\317\340\340\340" + "\332\332\336\16\16>\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0" + """3\0\0""3\0\0""3**R\321\321\321\342\342\342\364\364\364\270\270\306\0\0" + """3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3" + "55Y\202\202\212\206\206\206\210\210\210\216\216\216\227\227\227\237\237\237" + "\247\247\247\261\261\261\273\273\273\306\306\306\324\324\324\343\343\343" + "\236\236\260\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0" + """3\0\0""3\0\0""3\0\0""3\324\324\326\321\321\321\322\322\322\336\336\336" + "\357\357\357\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\364\343\343" + "\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0" + "\264ee\257HH\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231" + "\0\0\231\0\0\321\273\273\321\321\321\324\324\324\342\342\342\363\363\363" + "\375\375\375\377\377\377\377\377\377\364\343\343\231\0\0\231\0\0\231\0\0" + "\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\251^^\216\216\216\221\221" + "\221\263\263\263\335\335\335\366\366\366\376\376\376\377\377\377\240\21\21" + "\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0" + "\231\0\0\243[[rrrgggsss\203\203\203\222\222\222\236\236\236\247\247\247\260" + "\260\260\271\271\271\310\310\310\330\330\330\351\351\351\364\364\364\237" + "\17\17\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231" + "\0\0\231\0\0\224wwfffcccttt\205\205\205\224\224\224\237\237\237\246\246\246" + "\254\254\254\263\263\263\300\300\300\321\321\321\341\341\341\354\354\354" + "\231BJ\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231" + "\0\0A\0\35((P\205\205\205www\177\177\177\216\216\216\234\234\234\252\252" + "\252\271\271\271\315\315\315\335\335\335\353\353\353\366\366\366@@f\0\0""3" + "\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3gg\200\320" + "\320\320\347\347\347\262\262\300\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3" + "\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3eeyxxxpppvvv\201\201\201\213\213\213\225" + "\225\225\236\236\236\250\250\250\262\262\262\276\276\276\313\313\313\331" + "\331\331\350\350\350\365\365\365MMp\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0" + "\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\220\220\241\304\304\304\303\303" + "\303\322\322\322\351\351\351\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\315\202\202\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0" + "\231\0\0\231\0\0\272\247\247\304\236\236\231\0\0\231\0\0\231\0\0\231\0\0" + "\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\272hh\324\324\324\323\323\323\340" + "\340\340\361\361\361\374\374\374\377\377\377\377\377\377\315\203\203\231" + "\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\243" + "\222\222\213\213\213\232\232\232\301\301\301\347\347\347\372\372\372\377" + "\377\377\351\310\310\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231" + "\0\0\231\0\0\231\0\0\231\0\0\231\0\0\224\205\205pppnnn\204\204\204\231\231" + "\231\253\253\253\265\265\265\275\275\275\306\306\306\320\320\320\340\340" + "\340\355\355\355\366\366\366\343\275\275\231\0\0\231\0\0\231\0\0\231\0\0" + "\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\234\15\15|||ffflll\204\204" + "\204\232\232\232\253\253\253\265\265\265\274\274\274\301\301\301\312\312" + "\312\330\330\330\347\347\347\364\364\364\372\372\372\216\5\12\231\0\0\231" + "\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\20\0.ww\210" + "\224\224\224\222\222\222\240\240\240\256\256\256\272\272\272\307\307\307" + "\326\326\326\346\346\346\361\361\361\370\370\370\374\374\37411[\0\0""3\0" + "\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\16\16=\261\261\265" + "\326\326\326\323\323\331\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3" + "\0\0""3\0\0""3\0\0""3\0\0""3uu\202nnndddppp\207\207\207\232\232\232\246\246" + "\246\256\256\256\266\266\266\276\276\276\307\307\307\321\321\321\334\334" + "\334\351\351\351\364\364\364\372\372\372\270\270\306\0\0""3\0\0""3\0\0""3" + "\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3rr\211\271\271\271" + "\270\270\270\311\311\311\344\344\344\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\246!!\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0" + "\0\231\0\0\240\32\32\261\261\261\311\311\311\235\15\15\231\0\0\231\0\0\231" + "\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\235\15\15\330\330\330\324\324" + "\324\335\335\335\356\356\356\372\372\372\376\376\376\377\377\377\246!!\231" + "\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\237\32\32\224" + "\224\224\213\213\213\245\245\245\320\320\320\357\357\357\375\375\375\377" + "\377\377\305nn\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231" + "\0\0\231\0\0\231\0\0\237\32\32\206\206\206vvv\203\203\203\246\246\246\302" + "\302\302\324\324\324\331\331\331\336\336\336\344\344\344\353\353\353\363" + "\363\363\371\371\371\375\375\375\303ii\231\0\0\231\0\0\231\0\0\231\0\0\231" + "\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\244OO{{{rrr\206\206\206\251" + "\251\251\304\304\304\324\324\324\331\331\331\335\335\335\340\340\340\346" + "\346\346\356\356\356\366\366\366\374\374\374\337\306\311\231\0\0\231\0\0" + "\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\200\0\10\0\0""3" + "\254\254\260\266\266\266\300\300\300\320\320\320\332\332\332\341\341\341" + "\350\350\350\360\360\360\367\367\367\373\373\373\376\376\376\307\307\322" + "\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\207" + "\207\224\303\303\303\330\330\332\40\40L\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3" + "\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3eezoooaaaooo\216\216\216\261\261\261\307" + "\307\307\322\322\322\326\326\326\332\332\332\337\337\337\344\344\344\351" + "\351\351\360\360\360\366\366\366\374\374\374\376\376\376\365\365\367\0\0" + """3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3" + "qq\207\260\260\260\260\260\260\304\304\304\342\342\342\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\364\343\343\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231" + "\0\0\231\0\0\231\0\0\231\0\0\255mm\256\256\256\314\314\314\271[[\231\0\0" + "\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\315\245" + "\245\327\327\327\334\334\334\352\352\352\370\370\370\375\375\375\364\343" + "\343\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231" + "\0\0\251^^\216\216\216\221\221\221\263\263\263\335\335\335\366\366\366\376" + "\376\376\377\377\377\240\21\21\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231" + "\0\0\231\0\0\231\0\0\231\0\0\231\0\0\247]]\204\204\204\177\177\177\231\231" + "\231\303\303\303\355\355\355\377\377\377\377\377\377\377\377\377\370\370" + "\370\372\372\372\375\375\375\376\376\376\377\377\377\237\20\20\231\0\0\231" + "\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\240" + "\200\200}}}\202\202\202\242\242\242\312\312\312\373\373\373\377\377\377\377" + "\377\377\377\377\377\371\371\371\370\370\370\373\373\373\375\375\375\377" + "\377\377\237^h\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231" + "\0\0\231\0\0W\0\26))S\315\315\315\325\325\325\344\344\344\357\357\357\364" + "\364\364\366\366\366\371\371\371\373\373\373\375\375\375\377\377\377\313" + "\313\326\21\21@\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\15" + "\15<\213\213\226\264\264\264\323\323\323ww\221\0\0""3\0\0""3\0\0""3\0\0""3" + "\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3((P|||gggqqq\220\220\220\271\271" + "\271\331\331\331\363\363\363\375\375\375\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\373\373\373\375\375\375\376\376\376\377\377" + "\377\377\377\377\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3" + "\0\0""3\0\0""3\0\0""3pp\206\252\252\252\253\253\253\300\300\300\340\340\340" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\315\202\202\231\0\0\231\0\0\231\0\0" + "\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\247\235\235\254\254\254" + "\317\317\317\334\275\275\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0" + "\231\0\0\231\0\0\231\0\0\263II\334\334\334\336\336\336\352\352\352\367\367" + "\367\375\375\375\316\204\204\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231" + "\0\0\231\0\0\231\0\0\231\0\0\243\222\222\213\213\213\232\232\232\301\301" + "\301\347\347\347\372\372\372\377\377\377\351\311\311\231\0\0\231\0\0\231" + "\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\241" + "\220\220\204\204\204\213\213\213\256\256\256\331\331\331\376\376\376\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\351\310\310\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231" + "\0\0\231\0\0\231\0\0\231\0\0\234\15\15\220\220\220\203\203\203\225\225\225" + "\276\276\276\346\346\346\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\210\10\17\231" + "\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0b\0\22" + "y-<\251\\a\254`e\260ci\263gl\264hm\265im\266jn\250\\c\216BO^\22(L\0\32L\0" + "\32A\0\35\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\15\15>>d\213\213\242\216" + "\216\244\220\220\246\223\223\251[[|44\\\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3" + "\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3ccwmmm]]]jjj\214" + "\214\214\270\270\270\335\335\335\374\374\374\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\351\310\310\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231" + "\0\0\231\0\0\231\0\0\250tt\211\211\211\212\212\212\247\247\247\321\321\321" + "\366\366\366\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\344\274\274\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231" + "\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231" + "\0\0\252uu\214\214\214\222\222\222\264\264\264\337\337\337\366\366\366\376" + "\376\376\374\367\367\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231" + "\0\0\231\0\0\231\0\0\231\0\0\231\0\0\250tt\211\211\211\212\212\212\247\247" + "\247\321\321\321\366\366\366\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\374\367\367\231\0\0\231\0\0\231" + "\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\241" + "\220\220\210\210\210\222\222\222\265\265\265\335\335\335\376\376\376\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\206m\202\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231" + "\0\0\231\0\0\231\0\0\231\0\0\200\0\10EEf\216\216\216\202\202\202\225\225" + "\225\276\276\276\346\346\346\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\215\215\244\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0" + "\0""3\0\0""3\0\0""3\0\0""3\0\0""3\237\237\250\263\263\263\275\275\275\333" + "\333\333\360\360\360\370\370\370\240\240\262\15\15=\0\0""3\0\0""3\0\0""3" + "\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0" + "\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0" + """3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""355Y\202\202\207nnnbbbmmm\215" + "\215\215\270\270\270\335\335\335\374\374\374\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\305nn\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0" + "\0\231\0\0\231\0\0\231\0\0\232\220\220\203\203\203\217\217\217\264\264\264" + "\334\334\334\376\376\376\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\245\35\35\231\0\0\231\0\0\231\0\0\231\0\0\231\0" + "\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0" + "\0\231\0\0\231\0\0\233\221\221\205\205\205\227\227\227\301\301\301\347\347" + "\347\371\371\371\377\377\377\341\265\265\231\0\0\231\0\0\231\0\0\231\0\0" + "\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\232\220\220\203" + "\203\203\217\217\217\263\263\263\334\334\334\376\376\376\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\341" + "\265\265\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0" + "\231\0\0\231\0\0\237\32\32\217\217\217\206\206\206\233\233\233\304\304\304" + "\352\352\352\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377T\22,\231\0\0\231\0\0\231" + "\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0W\0\26}}\213\204\204" + "\204\205\205\205\243\243\243\317\317\317\365\365\365\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377CCh\0\0""3\0\0""3\0\0""3\0\0""3\0" + "\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\234\234\245\252\252\252\263" + "\263\263\320\320\320\346\346\346\361\361\361\360\360\360\312\312\32299`\0" + "\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0" + """3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3" + "\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3DDd\206\206\216\200\200\200rrr" + "mmmwww\223\223\223\271\271\271\335\335\335\374\374\374\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\376\376\376\237\20\20\231\0\0\231\0\0\231\0" + "\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\241((\204\204\204\200\200\200" + "\233\233\233\305\305\305\353\353\353\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\307ss\231\0\0\231\0\0\231" + "\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231" + "\0\0\231\0\0\231\0\0\231\0\0\241((\204\204\204\201\201\201\242\242\242\317" + "\317\317\357\357\357\374\374\374\376\376\376\274WW\231\0\0\231\0\0\231\0" + "\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\241((\204\204" + "\204\200\200\200\233\233\233\305\305\305\353\353\353\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\376\376" + "\376\274WW\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0" + "\0\231\0\0\231\0\0\245\\\\\203\203\203\205\205\205\245\245\245\320\320\320" + "\366\366\366\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\337\337\345\200\0\10\231\0\0\231\0\0" + "\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\31\0+\211\211\212" + "zzz\210\210\210\260\260\260\333\333\333\376\376\376\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377BBh\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3" + "\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\222\222\233\232\232\232\242\242" + "\242\302\302\302\337\337\337\355\355\355\356\356\356\351\351\351\346\346" + "\346\231\231\25299`\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0" + """3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3" + "\0\0""3\0\0""3\0\0""3\0\0""3((Puu\206\221\221\224\210\210\210}}}zzz}}}\213" + "\213\213\240\240\240\301\301\301\336\336\336\374\374\374\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\376\376\376\344\277\277\231\0\0\231\0\0" + "\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\233kkvvv\200\200" + "\200\250\250\250\324\324\324\370\370\370\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\376\376\376\354\325\325\231\0\0" + "\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0" + "\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\233kkvvv\201\201\201\255\255\255" + "\332\332\332\365\365\365\375\375\375\370\362\362\231\0\0\231\0\0\231\0\0" + "\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\233kkvv" + "v\200\200\200\250\250\250\324\324\324\370\370\370\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\376\376\376\370\363\363" + "\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0\231\0\0" + "\231\0\0\231\0\0\220\201\201www\205\205\205\257\257\257\333\333\333\376\376" + "\376\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\376\376\376}n\205\231\0\0\231\0\0\231\0\0\231\0\0\231\0" + "\0\231\0\0\231\0\0\231\0\0\231\0\0\211\0\5BBbvvvttt\222\222\222\300\300\300" + "\352\352\352\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\376\376\376??e\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0" + "\0""3\0\0""3\0\0""3\204\204\214\206\206\206\225\225\225\274\274\274\336\336" + "\336\357\357\357\360\360\360\352\352\352\343\343\343\336\336\336\332\332" + "\332\305\305\311\204\204\230GGi\15\15=\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3" + "\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""3\0\0""377\\__x\177" + "\177\215\232\232\234\222\222\222\211\211\211\202\202\202\202\202\202\206" + "\206\206\224\224\224\244\244\244\273\273\273\320\320\320\346\346\346\374" + "\374\374\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\374" + "\374\374\355\340\340\331\273\273\315\260\260\302\246\246\275\241\241\273" + "\237\237\271\236\236\266\233\233\253\222\222\233\204\204yuurrr\214\214\214" + "\274\274\274\345\345\345\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\373\373\373\364\364\364\326\267\267" + "\314\256\256\303\246\246\276\242\242\273\237\237\272\236\236\272\236\236" + "\272\236\236\272\236\236\272\236\236\272\236\236\271\236\236\266\233\233" + "\253\222\222\233\204\204yuurrr\214\214\214\276\276\276\347\347\347\372\372" + "\372\373\373\373\360\351\351\331\273\273\315\260\260\302\246\246\275\241" + "\241\273\237\237\272\236\236\272\236\236\271\236\236\266\233\233\253\222" + "\222\233\204\204yuurrr\214\214\214\274\274\274\345\345\345\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\374" + "\374\374\361\353\353\331\273\273\315\260\260\302\246\246\275\241\241\273" + "\237\237\272\236\236\272\236\236\270\235\235\265\232\232\252\221\221\231" + "\202\202uuusss\217\217\217\277\277\277\351\351\351\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\374\374\374\322\322\332\272\272\304\256\256\270\246\246\260\242\242\253" + "\237\237\250\236\236\247\236\236\247\234\234\245\225\225\236\210\210\220" + "||\177ooo}}}\244\244\244\322\322\322\367\367\367\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\374\374\374\322\322\332\272\272\304" + "\257\257\271\246\246\260\242\242\253\237\237\250\236\236\247\236\236\247" + "\235\235\246\232\232\243\221\221\232\203\203\213yyzzzz\225\225\225\303\303" + "\303\351\351\351\366\366\366\366\366\366\357\357\357\347\347\347\335\335" + "\335\324\324\324\315\315\315\306\306\306\303\303\303\303\303\303\300\300" + "\302\245\245\257\243\243\254pp\206oo\205oo\205oo\205oo\205oo\205oo\205\236" + "\236\247\234\234\245\256\256\260\251\251\251\235\235\235\223\223\223\215" + "\215\215\211\211\211\210\210\210\211\211\211\216\216\216\232\232\232\252" + "\252\252\300\300\300\322\322\322\344\344\344\366\366\366\376\376\376\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\376\376\376\371" + "\371\371\355\355\355\332\332\332\305\305\305\265\265\265\254\254\254\250" + "\250\250\245\245\245\241\241\241\226\226\226\207\207\207{{{\204\204\204\243" + "\243\243\320\320\320\366\366\366\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\376\376\376\370\370\370\354\354\354\331" + "\331\331\306\306\306\266\266\266\254\254\254\250\250\250\247\247\247\247" + "\247\247\247\247\247\247\247\247\247\247\247\247\247\247\245\245\245\241" + "\241\241\226\226\226\210\210\210|||\205\205\205\244\244\244\321\321\321\360" + "\360\360\373\373\373\366\366\366\353\353\353\331\331\331\305\305\305\265" + "\265\265\254\254\254\250\250\250\247\247\247\247\247\247\245\245\245\241" + "\241\241\226\226\226\207\207\207{{{\204\204\204\243\243\243\320\320\320\366" + "\366\366\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\376\376\376\371\371\371\355\355\355\332\332\332\305\305\305\265" + "\265\265\254\254\254\250\250\250\247\247\247\247\247\247\245\245\245\240" + "\240\240\225\225\225\205\205\205zzz\203\203\203\244\244\244\320\320\320\366" + "\366\366\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\376\376\376\371\371\371\356\356\356\333\333\333\306" + "\306\306\266\266\266\254\254\254\250\250\250\247\247\247\246\246\246\242" + "\242\242\232\232\232\214\214\214\200\200\200\201\201\201\232\232\232\302" + "\302\302\346\346\346\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\376\376\376\371\371\371\356\356\356\332\332\332\306\306\306\266" + "\266\266\254\254\254\250\250\250\247\247\247\247\247\247\245\245\245\240" + "\240\240\224\224\224\204\204\204zzz\204\204\204\246\246\246\322\322\322\366" + "\366\366\376\376\376\373\373\373\366\366\366\357\357\357\345\345\345\332" + "\332\332\317\317\317\307\307\307\301\301\301\275\275\275\272\272\272\266" + "\266\266\261\261\261\253\253\253\250\250\250\247\247\247\247\247\247\247" + "\247\247\247\247\247\247\247\247\246\246\246\243\243\243\236\236\236\231" + "\231\231\224\224\224\220\220\220\220\220\220\223\223\223\234\234\234\246" + "\246\246\263\263\263\304\304\304\324\324\324\345\345\345\367\367\367\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\376\376\376\367\367\367\352\352\352\326\326\326\303" + "\303\303\264\264\264\253\253\253\250\250\250\246\246\246\242\242\242\234" + "\234\234\226\226\226\231\231\231\250\250\250\307\307\307\346\346\346\376" + "\376\376\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\376\376\376\367\367\367\352\352\352\326\326\326\303\303\303\264" + "\264\264\253\253\253\250\250\250\247\247\247\247\247\247\247\247\247\247" + "\247\247\247\247\247\247\247\247\246\246\246\242\242\242\234\234\234\226" + "\226\226\231\231\231\251\251\251\307\307\307\346\346\346\370\370\370\374" + "\374\374\364\364\364\347\347\347\325\325\325\302\302\302\264\264\264\253" + "\253\253\250\250\250\247\247\247\247\247\247\246\246\246\242\242\242\234" + "\234\234\226\226\226\231\231\231\250\250\250\307\307\307\346\346\346\376" + "\376\376\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\376\376\376\367\367\367\352\352\352\326\326\326\303\303\303\264" + "\264\264\253\253\253\250\250\250\247\247\247\247\247\247\245\245\245\241" + "\241\241\233\233\233\224\224\224\227\227\227\247\247\247\306\306\306\346" + "\346\346\376\376\376\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\376\376\376\367\367\367\352\352\352\327" + "\327\327\303\303\303\264\264\264\253\253\253\250\250\250\247\247\247\246" + "\246\246\243\243\243\237\237\237\232\232\232\235\235\235\251\251\251\304" + "\304\304\337\337\337\374\374\374\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\376\376\376\370\370\370\353\353\353\327\327\327\303" + "\303\303\264\264\264\253\253\253\250\250\250\247\247\247\247\247\247\245" + "\245\245\241\241\241\233\233\233\223\223\223\226\226\226\247\247\247\306" + "\306\306\346\346\346\376\376\376\377\377\377\377\377\377\376\376\376\370" + "\370\370\361\361\361\350\350\350\335\335\335\326\326\326\316\316\316\310" + "\310\310\300\300\300\267\267\267\260\260\260\253\253\253\250\250\250\247" + "\247\247\247\247\247\247\247\247\247\247\247\247\247\247\246\246\246\243" + "\243\243\242\242\242\243\243\243\247\247\247\251\251\251\256\256\256\266" + "\266\266\304\304\304\321\321\321\334\334\334\352\352\352\367\367\367\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\376\376\376\371\371\371\356" + "\356\356\337\337\337\320\320\320\305\305\305\300\300\300\275\275\275\274" + "\274\274\272\272\272\271\271\271\273\273\273\305\305\305\324\324\324\346" + "\346\346\374\374\374\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\376\376\376\371\371\371\356\356\356\337" + "\337\337\320\320\320\305\305\305\300\300\300\275\275\275\275\275\275\275" + "\275\275\275\275\275\275\275\275\275\275\275\275\275\275\274\274\274\272" + "\272\272\271\271\271\273\273\273\306\306\306\324\324\324\347\347\347\374" + "\374\374\377\377\377\375\375\375\367\367\367\355\355\355\336\336\336\320" + "\320\320\305\305\305\300\300\300\275\275\275\275\275\275\275\275\275\274" + "\274\274\272\272\272\271\271\271\273\273\273\305\305\305\324\324\324\346" + "\346\346\374\374\374\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\376\376\376\371\371\371\356\356\356\337" + "\337\337\320\320\320\305\305\305\300\300\300\275\275\275\275\275\275\275" + "\275\275\274\274\274\272\272\272\271\271\271\272\272\272\305\305\305\323" + "\323\323\346\346\346\374\374\374\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\376\376\376\371" + "\371\371\357\357\357\337\337\337\320\320\320\305\305\305\300\300\300\275" + "\275\275\275\275\275\275\275\275\273\273\273\273\273\273\275\275\275\310" + "\310\310\326\326\326\347\347\347\374\374\374\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\376\376\376\371\371\371\357" + "\357\357\337\337\337\320\320\320\305\305\305\300\300\300\275\275\275\275" + "\275\275\275\275\275\274\274\274\272\272\272\271\271\271\272\272\272\305" + "\305\305\323\323\323\346\346\346\374\374\374\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\374\374\374\366\366\366\357\357\357\353" + "\353\353\345\345\345\336\336\336\323\323\323\312\312\312\304\304\304\300" + "\300\300\275\275\275\275\275\275\275\275\275\275\275\275\275\275\275\275" + "\275\275\275\275\275\273\273\273\274\274\274\301\301\301\313\313\313\322" + "\322\322\330\330\330\335\335\335\352\352\352\366\366\366\376\376\376\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\376\376\376\370\370\370\357\357\357\347\347\347\342\342\342\340" + "\340\340\336\336\336\336\336\336\335\335\335\336\336\336\340\340\340\354" + "\354\354\367\367\367\376\376\376\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\376" + "\376\376\370\370\370\357\357\357\347\347\347\342\342\342\340\340\340\336" + "\336\336\336\336\336\336\336\336\336\336\336\336\336\336\336\336\336\336" + "\336\336\336\336\336\335\335\335\336\336\336\341\341\341\354\354\354\367" + "\367\367\377\377\377\377\377\377\377\377\377\377\377\377\375\375\375\367" + "\367\367\356\356\356\347\347\347\342\342\342\340\340\340\336\336\336\336" + "\336\336\336\336\336\336\336\336\335\335\335\336\336\336\340\340\340\354" + "\354\354\367\367\367\376\376\376\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\376" + "\376\376\370\370\370\357\357\357\347\347\347\342\342\342\340\340\340\336" + "\336\336\336\336\336\336\336\336\336\336\336\335\335\335\336\336\336\340" + "\340\340\354\354\354\367\367\367\376\376\376\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\376\376\376\370\370\370\357\357\357\347\347\347\342" + "\342\342\340\340\340\336\336\336\336\336\336\336\336\336\335\335\335\336" + "\336\336\341\341\341\355\355\355\370\370\370\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\376\376\376\370\370\370\357\357\357\347\347\347\342\342\342\340" + "\340\340\336\336\336\336\336\336\336\336\336\336\336\336\335\335\335\336" + "\336\336\340\340\340\354\354\354\367\367\367\376\376\376\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\376\376\376\372\372\372\363\363\363\353\353\353\345" + "\345\345\342\342\342\340\340\340\336\336\336\336\336\336\336\336\336\336" + "\336\336\336\336\336\336\336\336\336\336\336\335\335\335\337\337\337\343" + "\343\343\355\355\355\366\366\366\375\375\375\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377", +}; + +static const char* RGB[] = {"R", "G", "B"}; + + + +NITF_BOOL populateFileHeader(nitf_Record *record, const char* title, + nitf_Error *error) +{ + /* the file header is already created, so just grab it */ + nitf_FileHeader *header = record->header; + + +/* if (!nitf_Field_setUint32(header->complianceLevel, 3, error)) */ +/* goto CATCH_ERROR; */ + if (!nitf_Field_setString(header->originStationID, "SF.net", error)) + goto CATCH_ERROR; + /* the filedatetime can get auto-populated at write-time now, if blank */ + /*if (!nitf_Field_setString(header->fileDateTime, "20080812000000", error)) + goto CATCH_ERROR;*/ + if (!nitf_Field_setString(header->fileTitle, title, error)) + goto CATCH_ERROR; + + return NITF_SUCCESS; + + CATCH_ERROR: + return NITF_FAILURE; +} + + +NITF_BOOL setCornersFromDMSBox(nitf_ImageSubheader* header, nitf_Error * error) +{ + /* + * You could do this in degrees as easily + * but this way we get to show off some new utilities + */ + int latTopDMS[3] = { 42, 17, 50 }; + int latBottomDMS[3] = { 42, 15, 14 }; + int lonEastDMS[3] = { -83, 42, 12 }; + int lonWestDMS[3] = { -83, 45, 44 }; + + double latTopDecimal = + nitf_Utils_geographicToDecimal(latTopDMS[0], + latTopDMS[1], + latTopDMS[2]); + + double latBottomDecimal = + nitf_Utils_geographicToDecimal(latBottomDMS[0], + latBottomDMS[1], + latBottomDMS[2]); + + double lonEastDecimal = + nitf_Utils_geographicToDecimal(lonEastDMS[0], + lonEastDMS[1], + lonEastDMS[2]); + + + double lonWestDecimal = + nitf_Utils_geographicToDecimal(lonWestDMS[0], + lonWestDMS[1], + lonWestDMS[2]); + + double corners[4][2]; + corners[0][0] = latTopDecimal; corners[0][1] = lonWestDecimal; + corners[1][0] = latTopDecimal; corners[1][1] = lonEastDecimal; + corners[2][0] = latBottomDecimal; corners[2][1] = lonEastDecimal; + corners[3][0] = latBottomDecimal; corners[3][1] = lonWestDecimal; + + return nitf_ImageSubheader_setCornersFromLatLons(header, + NITF_CORNERS_DECIMAL, + corners, + error); + + +} + +NITF_BOOL addImageSegment(nitf_Record *record, nitf_Error *error) +{ + nitf_ImageSegment *segment = NULL; + nitf_ImageSubheader *header = NULL; + nitf_BandInfo **bands = NULL; + + double corners[4][2]; + int i; + + segment = nitf_Record_newImageSegment(record, error); + if (!segment) + goto CATCH_ERROR; + + /* grab the subheader */ + header = segment->subheader; + + /* populate some fields */ + if (!nitf_Field_setString(header->imageId, "NITRO-TEST", error)) + goto CATCH_ERROR; + /* fake the date */ + if (!nitf_Field_setString(header->imageDateAndTime, "20080812000000", error)) + goto CATCH_ERROR; + + /* Set the geo-corners to Ann Arbor, MI */ + if (!setCornersFromDMSBox(header, error)) + goto CATCH_ERROR; + + /* create a BandInfo buffer */ + bands = (nitf_BandInfo **) NITF_MALLOC(sizeof(nitf_BandInfo *) * 3); + if (bands == NULL) + { + nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO), + NITF_CTXT, NITF_ERR_MEMORY); + goto CATCH_ERROR; + } + + + for (i = 0; i < 3; ++i) + { + bands[i] = nitf_BandInfo_construct(error); + if (!bands[i]) + goto CATCH_ERROR; + + if (!nitf_BandInfo_init(bands[i], + RGB[i], /* The band representation, Nth band */ + " ", /* The band subcategory */ + "N", /* The band filter condition */ + " ", /* The band standard image filter code */ + 0, /* The number of look-up tables */ + 0, /* The number of entries/LUT */ + NULL, /* The look-up tables */ + error)) + goto CATCH_ERROR; + } + + /* set the pixel information */ + if (!nitf_ImageSubheader_setPixelInformation(header, /* header */ + "INT", /* Pixel value type */ + 8, /* Number of bits/pixel */ + 8, /* Actual number of bits/pixel */ + "R", /* Pixel justification */ + "RGB", /* Image representation */ + "VIS", /* Image category */ + 3, /* Number of bands */ + bands, /* Band information object list */ + error)) + goto CATCH_ERROR; + + /* for fun, let's add a comment */ + if (nitf_ImageSubheader_insertImageComment(header, "NITF generated by NITRO", + 0, error) < 0) + goto CATCH_ERROR; + + /* set the blocking info */ + if (!nitf_ImageSubheader_setBlocking(header, + NITRO_IMAGE.height, /*!< The number of rows */ + NITRO_IMAGE.width, /*!< The number of columns */ + NITRO_IMAGE.height, /*!< The number of rows/block */ + NITRO_IMAGE.width, /*!< The number of columns/block */ + "P", /*!< Image mode */ + error)) + goto CATCH_ERROR; + + + return NITF_SUCCESS; + + CATCH_ERROR: + return NITF_FAILURE; +} + + +NITF_BOOL writeNITF(nitf_Record *record, const char* filename, nitf_Error *error) +{ + nitf_IOHandle out; + nitf_Writer *writer = NULL; + nitf_ImageWriter *imageWriter = NULL; + nitf_ImageSource *imageSource; + nitf_Uint32 i; + + /* create the IOHandle */ + out = nitf_IOHandle_create(filename, NITF_ACCESS_WRITEONLY, + NITF_CREATE, error); + + if (NITF_INVALID_HANDLE(out)) + goto CATCH_ERROR; + + writer = nitf_Writer_construct(error); + if (!writer) + goto CATCH_ERROR; + + /* prepare the writer to write this record */ + if (!nitf_Writer_prepare(writer, record, out, error)) + goto CATCH_ERROR; + + /* get a new ImageWriter for the 1st image (index 0) */ + imageWriter = nitf_Writer_newImageWriter(writer, 0, NULL, error); + if (!imageWriter) + goto CATCH_ERROR; + + /* create an ImageSource for our embedded image */ + imageSource = nitf_ImageSource_construct(error); + if (!imageSource) + goto CATCH_ERROR; + + /* make one bandSource per band */ + for (i = 0; i < 3; ++i) + { + nitf_BandSource *bandSource = nitf_MemorySource_construct( + (char*)NITRO_IMAGE.data, NITRO_IMAGE.width * NITRO_IMAGE.height, + i, 1, 2, error); + if (!bandSource) + goto CATCH_ERROR; + + /* attach the band to the image */ + if (!nitf_ImageSource_addBand(imageSource, bandSource, error)) + goto CATCH_ERROR; + } + + /* enable caching within the writer */ + nitf_ImageWriter_setWriteCaching(imageWriter, 1); + + /* attach the ImageSource to the writer */ + if (!nitf_ImageWriter_attachSource(imageWriter, imageSource, error)) + goto CATCH_ERROR; + + /* finally, write it! */ + if (!nitf_Writer_write(writer, error)) + { + nitf_Error_print(error, stderr, "Error writing up write"); + exit(1); + } + + /* cleanup */ + nitf_IOHandle_close(out); + nitf_Writer_destruct(&writer); + return NITF_SUCCESS; + + CATCH_ERROR: + if (writer) nitf_Writer_destruct(&writer); + return NITF_FAILURE; +} + + +TEST_CASE_ARGS(testCreate) +{ + nitf_Record *record = NULL; + nitf_Error error; + char* outname = argc > 1 ? argv[1] : "test_create.ntf"; + + TEST_ASSERT((record = nitf_Record_construct(NITF_VER_21, &error))); + TEST_ASSERT(populateFileHeader(record, outname, &error)); + TEST_ASSERT(addImageSegment(record, &error)); + TEST_ASSERT(writeNITF(record, outname, &error)); + nitf_Record_destruct(&record); +} + +TEST_CASE_ARGS(testRead) +{ + nitf_Reader *reader = NULL; + nitf_Record *record = NULL; + nitf_Error error; + nitf_IOHandle io; + char* outname = argc > 1 ? argv[1] : "test_create.ntf"; + + io = nitf_IOHandle_create(outname, NITF_ACCESS_READONLY, NITF_OPEN_EXISTING, &error); + reader = nitf_Reader_construct(&error); + TEST_ASSERT(reader); + record = nitf_Reader_read(reader, io, &error); + TEST_ASSERT(record); + nitf_Reader_destruct(&reader); + nitf_Record_destruct(&record); +} + +int main(int argc, char **argv) +{ + CHECK_ARGS(testCreate); + CHECK_ARGS(testRead); + return 0; +} + diff --git a/modules/c/nitf/unittests/test_field.c b/modules/c/nitf/unittests/test_field.c new file mode 100644 index 000000000..e6f4d22bd --- /dev/null +++ b/modules/c/nitf/unittests/test_field.c @@ -0,0 +1,105 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include +#include "Test.h" + +TEST_CASE( testField) +{ + char fhdr_str[NITF_FHDR_SZ + 1]; + char ubin_str[10]; + char hl_str[NITF_HL_SZ + 1]; + double doubleData; + float floatData; + nitf_Field *fhdr = NULL, *ubin = NULL, *hl = NULL, *realField = NULL; + + nitf_Error error; + nitf_Int32 int32 = 16801; + fhdr = nitf_Field_construct(NITF_FHDR_SZ, NITF_BCS_A, &error); + ubin = nitf_Field_construct(4, NITF_BINARY, &error); + hl = nitf_Field_construct(NITF_HL_SZ, NITF_BCS_N, &error); + realField = nitf_Field_construct(NITF_HL_SZ, NITF_BCS_N, &error); + + TEST_ASSERT(fhdr); + TEST_ASSERT(ubin); + TEST_ASSERT(hl); + TEST_ASSERT(realField); + + printf("%d\n", int32); + nitf_Field_setRawData(fhdr, "NIT", 3, &error); + nitf_Field_setRawData(ubin, &int32, 4, &error); + nitf_Field_setRawData(hl, "000142", 6, &error); + nitf_Field_setRawData(realField, "142.56", 6, &error); + + TEST_ASSERT(nitf_Field_get(fhdr, fhdr_str, NITF_CONV_STRING, NITF_FHDR_SZ + + 1, &error)); + printf("FHDR: [%s]\n", fhdr_str); + TEST_ASSERT_EQ_STR(fhdr_str, "NIT "); + + TEST_ASSERT(nitf_Field_get(hl, hl_str, NITF_CONV_STRING, NITF_HL_SZ + 1, + &error)); + printf("HL (str): [%s]\n", hl_str); + TEST_ASSERT_EQ_STR(hl_str, "000142"); + + TEST_ASSERT(nitf_Field_get(hl, &int32, NITF_CONV_INT, 4, &error)); + printf("HL: [%d]\n", int32); + TEST_ASSERT_EQ_INT(int32, 142); + + TEST_ASSERT(nitf_Field_get(realField, hl_str, NITF_CONV_STRING, NITF_HL_SZ + + 1, &error)); + printf("REAL (str): [%s]\n", hl_str); + TEST_ASSERT_EQ_STR(hl_str, "142.56"); + + TEST_ASSERT(nitf_Field_get(realField, &doubleData, NITF_CONV_REAL, + sizeof(double), &error)); + printf("REAL (double): [%f]\n", doubleData); + TEST_ASSERT_EQ_FLOAT((float)doubleData, 142.56f); + + TEST_ASSERT(nitf_Field_get(realField, &floatData, NITF_CONV_REAL, + sizeof(float), &error)); + printf("REAL (float): [%f]\n", floatData); + TEST_ASSERT_EQ_FLOAT(floatData, 142.56f); + + TEST_ASSERT(nitf_Field_get(ubin, &int32, NITF_CONV_INT, 4, &error)); + printf("UBIN: [%d]\n", int32); + TEST_ASSERT_EQ_INT(int32, 16801); + + TEST_ASSERT(nitf_Field_get(ubin, ubin_str, NITF_CONV_STRING, 10, &error)); + printf("UBIN (str): [%s]\n", ubin_str); + TEST_ASSERT_EQ_STR(ubin_str, "16801"); + + nitf_Field_destruct(&fhdr); + nitf_Field_destruct(&ubin); + nitf_Field_destruct(&hl); + nitf_Field_destruct(&realField); + + TEST_ASSERT_NULL(fhdr); + TEST_ASSERT_NULL(ubin); + TEST_ASSERT_NULL(hl); + TEST_ASSERT_NULL(realField); +} + +int main(int argc, char **argv) +{ + CHECK(testField); + return 0; +} diff --git a/modules/c/nitf/unittests/test_mem_source.c b/modules/c/nitf/unittests/test_mem_source.c new file mode 100644 index 000000000..28d1352e3 --- /dev/null +++ b/modules/c/nitf/unittests/test_mem_source.c @@ -0,0 +1,107 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include +#include "Test.h" + +#define MEMBUF "ABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABC" +#define BAND1 "AAAAAAAAAAAAAAAA" +#define BAND2 "BBBBBBBBBBBBBBBB" +#define BAND3 "CCCCCCCCCCCCCCCC" +#define MEMSIZE strlen(MEMBUF) +#define NUM_BANDS 3 + +TEST_CASE(testMemorySource) +{ + /* Get the error object */ + nitf_Error error; + int bandSize = MEMSIZE / NUM_BANDS; + int numBytesPerPix = 1; + char *band_0 = NULL, *band_1 = NULL, *band_2 = NULL, *all_bands = NULL; + + /* Construct the band sources */ + nitf_BandSource *bs0 = nitf_MemorySource_construct(MEMBUF, MEMSIZE, 0, + numBytesPerPix, + NUM_BANDS - 1, &error); + nitf_BandSource *bs1 = nitf_MemorySource_construct(MEMBUF, MEMSIZE, 1, + numBytesPerPix, + NUM_BANDS - 1, &error); + nitf_BandSource *bs2 = nitf_MemorySource_construct(MEMBUF, MEMSIZE, 2, + numBytesPerPix, + NUM_BANDS - 1, &error); + nitf_BandSource *all = nitf_MemorySource_construct(MEMBUF, MEMSIZE, 0, + numBytesPerPix, 0, + &error); + + TEST_ASSERT(bs0); + TEST_ASSERT(bs1); + TEST_ASSERT(bs2); + TEST_ASSERT(all); + + /* Construct in memory band buffers for testing -- 0 terminate strings */ + band_0 = (char *) NITF_MALLOC(bandSize + 1); + band_1 = (char *) NITF_MALLOC(bandSize + 1); + band_2 = (char *) NITF_MALLOC(bandSize + 1); + all_bands = (char *) NITF_MALLOC(MEMSIZE + 1); + band_0[bandSize] = 0; + band_1[bandSize] = 0; + band_2[bandSize] = 0; + all_bands[MEMSIZE] = 0; + + /* Read half of the info for one band. This makes sure that we */ + /* are capable of picking up where we left off */ + bs0->iface->read(bs0->data, band_0, (MEMSIZE / NUM_BANDS / 2), &error); + bs1->iface->read(bs1->data, band_1, (MEMSIZE / NUM_BANDS / 2), &error); + bs2->iface->read(bs2->data, band_2, (MEMSIZE / NUM_BANDS / 2), &error); + + /* Pick up where we left off and keep going */ + bs0->iface->read(bs0->data, &band_0[MEMSIZE / NUM_BANDS / 2], (MEMSIZE + / NUM_BANDS / 2), &error); + bs1->iface->read(bs1->data, &band_1[MEMSIZE / NUM_BANDS / 2], (MEMSIZE + / NUM_BANDS / 2), &error); + bs2->iface->read(bs2->data, &band_2[MEMSIZE / NUM_BANDS / 2], (MEMSIZE + / NUM_BANDS / 2), &error); + all->iface->read(all->data, all_bands, MEMSIZE, &error); + + TEST_ASSERT_EQ_STR(band_0, BAND1); + TEST_ASSERT_EQ_STR(band_1, BAND2); + TEST_ASSERT_EQ_STR(band_2, BAND3); + TEST_ASSERT_EQ_STR(all_bands, MEMBUF); + + NITF_FREE(band_0); + NITF_FREE(band_1); + NITF_FREE(band_2); + NITF_FREE(all_bands); + nitf_BandSource_destruct(&bs0); + nitf_BandSource_destruct(&bs1); + nitf_BandSource_destruct(&bs2); + + TEST_ASSERT_NULL(bs0); + TEST_ASSERT_NULL(bs1); + TEST_ASSERT_NULL(bs2); +} + +int main(int argc, char **argv) +{ + CHECK(testMemorySource); + return 0; +} diff --git a/modules/c/nitf/unittests/test_zero_field.c b/modules/c/nitf/unittests/test_zero_field.c new file mode 100644 index 000000000..6187b53f4 --- /dev/null +++ b/modules/c/nitf/unittests/test_zero_field.c @@ -0,0 +1,37 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include +#include "Test.h" + +TEST_CASE( testZeroField) +{ + nitf_Error error; + nitf_Field *field = nitf_Field_construct(0, NITF_BCS_A, &error); + TEST_ASSERT_NULL(field); +} + +int main(int argc, char **argv) +{ + CHECK(testZeroField); + return 0; +} diff --git a/modules/c/nitf/wscript b/modules/c/nitf/wscript new file mode 100644 index 000000000..3ece38332 --- /dev/null +++ b/modules/c/nitf/wscript @@ -0,0 +1,45 @@ +import os, subprocess +from waflib import Options +from os.path import splitext, dirname, join + +NAME = 'nitf' +MAINTAINER = 'tzellman@users.sourceforge.net gojira_1@users.sourceforge.net' +VERSION = '2.7' +MODULE_DEPS = 'nrt' +LANG = 'c' +DEFINES = 'NITF_MODULE_EXPORTS' +TEST_FILTER = 'test_1band_rw_line.c ' \ + 'test_fileIO.c ' \ + 'test_hash_table_2.c ' \ + 'test_writer_s.c ' \ + 'test_des_read.c ' \ + 'test_read_acftb.c ' \ + 'test_add_masks.c ' \ + 'test_plugin_reg_1.c ' \ + 'test_des_write.c ' \ + 'test_ImageIO_support.c ' \ + 'test_make_pattern.c ' \ + 'test_des.c ' \ + 'test_ext_iter.c ' \ + 'test_ImageIO_read_data.c ' \ + 'test_ImageIO_writePattern.c ' \ + 'test_static_plugin.c' + +SUBDIRS = 'shared apps' + +configure = options = distclean = lambda p: None + +def build(bld): + env = bld.module(**globals()) + bld.recurse(filter(lambda x: os.path.exists(os.path.join(bld.path.abspath(), x)), + SUBDIRS.split())) + + #run doxygen + if 'DOXYGEN' in env and Options.is_install: + bld(rule='${DOXYGEN}', cwd=bld.path.abspath(), always=True) + try: + htmlDocs = bld.path.find_dir('doc/html') + for f in htmlDocs.find_iter(): + relpath = f.path_from(htmlDocs) + bld.install_files('${PREFIX}/share/doc/nitf/c/%s' % relpath, f.abspath()) + except:{} diff --git a/modules/c/nrt/COPYING b/modules/c/nrt/COPYING new file mode 100644 index 000000000..94a9ed024 --- /dev/null +++ b/modules/c/nrt/COPYING @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/modules/c/nrt/COPYING.LESSER b/modules/c/nrt/COPYING.LESSER new file mode 100644 index 000000000..fc8a5de7e --- /dev/null +++ b/modules/c/nrt/COPYING.LESSER @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/modules/c/nrt/Doxyfile b/modules/c/nrt/Doxyfile new file mode 100644 index 000000000..e4195f747 --- /dev/null +++ b/modules/c/nrt/Doxyfile @@ -0,0 +1,1040 @@ +# Doxyfile 1.3-rc3 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# General configuration options +#--------------------------------------------------------------------------- + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = NITF +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = 2.5 + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = doc + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, +# Finnish, French, German, Greek, Hungarian, Italian, Japanese, Japanese-en +# (Japanese with english messages), Korean, Norwegian, Polish, Portuguese, +# Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish and Ukrainian. + +OUTPUT_LANGUAGE = English + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these class will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited +# members of a class in the documentation of that class as if those members were +# ordinary class members. Constructors, destructors and assignment operators of +# the base classes will not be shown. + +INLINE_INHERITED_MEMB = YES + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = NO + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. It is allowed to use relative paths in the argument list. + +STRIP_FROM_PATH = + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower case letters. If set to YES upper case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# users are adviced to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like the Qt-style comments (thus requiring an +# explict @brief command for a brief description. + +JAVADOC_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the DETAILS_AT_TOP tag is set to YES then Doxygen +# will output the detailed description near the top, like JavaDoc. +# If set to NO, the detailed description appears after the member +# documentation. + +DETAILS_AT_TOP = YES + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# reimplements. + +INHERIT_DOCS = YES + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 8 + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consist of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. +# For instance some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = YES + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources +# only. Doxygen will then generate output that is more tailored for Java. +# For instance namespaces will be presented as packages, qualified scopes +# will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp +# *.h++ *.idl *.odl + +FILE_PATTERNS = *.h + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = shared include/nitf/unused include/nitf/old tests build + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or directories +# that are symbolic links (a Unix filesystem feature) are excluded from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. + +EXCLUDE_PATTERNS = *tests/* *.c + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = *.xcpp + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = YES + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. + +INPUT_FILTER = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES (the default) +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = YES + +# If the REFERENCES_RELATION tag is set to YES (the default) +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet + +HTML_STYLESHEET = + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output dir. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non empty doxygen will try to run +# the html help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the Html help documentation and to the tree view. + +TOC_EXPAND = NO + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 4 + +# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be +# generated containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (for instance Mozilla, +# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are +# probably better off using the HTML help feature. + +GENERATE_TREEVIEW = YES + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = NO + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = NO + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimised for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assigments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_XML = NO + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = YES + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_PREDEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. + +PREDEFINED = NITFAPI(X)=X __cplusplus=1 NITF_CXX_GUARD NITF_CXX_ENDGUARD + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = NO + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse the +# parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::addtions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES tag can be used to specify one or more tagfiles. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = nitf.tag + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in Html, RTF and LaTeX) for classes with base or +# super classes. Setting the tag to NO turns the diagrams off. Note that this +# option is superceded by the HAVE_DOT option below. This is only a fallback. It is +# recommended to install and use dot, since it yield more powerful graphs. + +CLASS_DIAGRAMS = YES + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found on the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_WIDTH = 1024 + +# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_HEIGHT = 1024 + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermedate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES + +#--------------------------------------------------------------------------- +# Configuration::addtions related to the search engine +#--------------------------------------------------------------------------- + +# The SEARCHENGINE tag specifies whether or not a search engine should be +# used. If set to NO the values of all tags below this one will be ignored. + +SEARCHENGINE = NO + +# The CGI_NAME tag should be the name of the CGI script that +# starts the search engine (doxysearch) with the correct parameters. +# A script with this name will be generated by doxygen. + +CGI_NAME = search.cgi + +# The CGI_URL tag should be the absolute URL to the directory where the +# cgi binaries are located. See the documentation of your http daemon for +# details. + +CGI_URL = + +# The DOC_URL tag should be the absolute URL to the directory where the +# documentation is located. If left blank the absolute path to the +# documentation, with file:// prepended to it, will be used. + +DOC_URL = + +# The DOC_ABSPATH tag should be the absolute path to the directory where the +# documentation is located. If left blank the directory on the local machine +# will be used. + +DOC_ABSPATH = + +# The BIN_ABSPATH tag must point to the directory where the doxysearch binary +# is installed. + +BIN_ABSPATH = /usr/local/bin/ + +# The EXT_DOC_PATHS tag can be used to specify one or more paths to +# documentation generated for other projects. This allows doxysearch to search +# the documentation for these projects as well. + +EXT_DOC_PATHS = diff --git a/modules/c/nrt/include/import/nrt.h b/modules/c/nrt/include/import/nrt.h new file mode 100644 index 000000000..f66bc6fd9 --- /dev/null +++ b/modules/c/nrt/include/import/nrt.h @@ -0,0 +1,45 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __IMPORT_NRT_H__ +#define __IMPORT_NRT_H__ + +#include "nrt/DateTime.h" +#include "nrt/Debug.h" +#include "nrt/Defines.h" +#include "nrt/Directory.h" +#include "nrt/DLL.h" +#include "nrt/Error.h" +#include "nrt/HashTable.h" +#include "nrt/IntStack.h" +#include "nrt/IOHandle.h" +#include "nrt/IOInterface.h" +#include "nrt/List.h" +#include "nrt/Memory.h" +#include "nrt/Pair.h" +#include "nrt/Sync.h" +#include "nrt/System.h" +#include "nrt/Tree.h" +#include "nrt/Types.h" +#include "nrt/Utils.h" + +#endif diff --git a/modules/c/nrt/include/nrt/DLL.h b/modules/c/nrt/include/nrt/DLL.h new file mode 100644 index 000000000..b8cc296b8 --- /dev/null +++ b/modules/c/nrt/include/nrt/DLL.h @@ -0,0 +1,104 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NRT_DLL_H__ +#define __NRT_DLL_H__ + +#include "nrt/Defines.h" +#include "nrt/Types.h" +#include "nrt/Memory.h" +#include "nrt/Error.h" + +#ifdef WIN32 +/* Under windows, a dynamic shared object is a DLL */ +# define NRT_DLL_EXTENSION ".dll" +#else +/* + * BE WARY: Under Unix, we expect a DSO to have a .so extension, + * in addition to the NRT_PLUGIN_PATH. That means that, + * despite a weak type extension system, your plugin won't + * get loaded without an .so extension. + */ +# define NRT_DLL_EXTENSION ".so" +#endif + +/*! + * \struct nrt_DLL + * \brief The C structure for loading a DLL + */ +typedef struct _NRT_DLL +{ + char *libname; /* The name of the library */ + NRT_NATIVE_DLL lib; /* A handle to the library */ +} nrt_DLL; + +NRT_CXX_GUARD +/*! + * 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 + */ +NRTAPI(nrt_DLL *) nrt_DLL_construct(nrt_Error * error); + +/*! + * Destroy the dll object. If the lib value is not null, + * calls nrt_DLL_unload(). NULLs the pointer + * \param dll A double pointer to the object + */ +NRTAPI(void) nrt_DLL_destruct(nrt_DLL ** dll); + +/*! + * Load the DLL object with an actual library. This is + * the equivalent of LoadLibrary() in windows. + * \param dll The DLL to load to + * \param libname The libname to use (this sets the value in the DLL object) + * \param error An error object to populate if there is a problem + * \return A status to be tested using NRT_FAILURE() + */ +NRTAPI(NRT_BOOL) nrt_DLL_load(nrt_DLL * dll, const char *libname, + nrt_Error * error); + +/*! + * Unload the structure. This may shrink the executable size. + * \param dll The object to unload + * \param error An error to be populated on failure + * \return A status to be tested using NRT_FAILURE() + */ +NRTAPI(NRT_BOOL) nrt_DLL_unload(nrt_DLL * dll, nrt_Error * error); + +/*! + * Returns a pointer to a DLL function by the name + * \param dll The DLL to retrieve from + * \param function The FARPROC function to call + * \param error Object to populate on error + * \return A pointer to the FARPROC function + */ +NRTAPI(NRT_DLL_FUNCTION_PTR) nrt_DLL_retrieve(nrt_DLL * dll, + const char *function, + nrt_Error * error); + +NRTAPI(NRT_BOOL) nrt_DLL_isValid(nrt_DLL * dll); + +NRT_CXX_ENDGUARD +#endif diff --git a/modules/c/nrt/include/nrt/DateTime.h b/modules/c/nrt/include/nrt/DateTime.h new file mode 100644 index 000000000..db64d5f32 --- /dev/null +++ b/modules/c/nrt/include/nrt/DateTime.h @@ -0,0 +1,145 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NRT_DATE_TIME_H__ +#define __NRT_DATE_TIME_H__ + +#include "nrt/System.h" +#include "nrt/Utils.h" + +NRT_CXX_GUARD +/*! + * The DateTime structure represents time. All dates are stored to reflect the + * coordinated universal time (UTC). The precision depends on the host machine. + * In many cases, seconds is the highest amount of granularity. + */ +typedef struct _NRT_DateTime +{ + int year; + int month; + int dayOfMonth; + int dayOfWeek; + int dayOfYear; + int hour; + int minute; + double second; + double timeInMillis; +} nrt_DateTime; + +/*! + * Returns a DateTime object representing the current moment in time. + */ +NRTAPI(nrt_DateTime *) nrt_DateTime_now(nrt_Error *); + +/*! + * Returns a DateTime object created from the milliseconds since the epoch: + * January 1, 1970, 00:00:00 GMT. + */ +NRTAPI(nrt_DateTime *) nrt_DateTime_fromMillis(double millis, nrt_Error *); + +/*! + * Sets the year of a DateTime object and updates the timeInMillis. + */ +NRTAPI(NRT_BOOL) nrt_DateTime_setYear(nrt_DateTime * dateTime, int year, + nrt_Error * error); + +/*! + * Sets the month of a DateTime object and updates the timeInMillis. + */ +NRTAPI(NRT_BOOL) nrt_DateTime_setMonth(nrt_DateTime * dateTime, int month, + nrt_Error * error); + +/*! + * Sets the dayOfMonth of a DateTime object and updates the timeInMillis. + */ +NRTAPI(NRT_BOOL) nrt_DateTime_setDayOfMonth(nrt_DateTime * dateTime, + int dayOfMonth, nrt_Error * error); + +/*! + * Sets the hour of a DateTime object and updates the timeInMillis. + */ +NRTAPI(NRT_BOOL) nrt_DateTime_setHour(nrt_DateTime * dateTime, int hour, + nrt_Error * error); + +/*! + * Sets the minute of a DateTime object and updates the timeInMillis. + */ +NRTAPI(NRT_BOOL) nrt_DateTime_setMinute(nrt_DateTime * dateTime, int minute, + nrt_Error * error); + +/*! + * Sets the second of a DateTime object and updates the timeInMillis. + */ +NRTAPI(NRT_BOOL) nrt_DateTime_setSecond(nrt_DateTime * dateTime, double second, + nrt_Error * error); + +/*! + * Sets the timeInMillis of a DateTime object and updates + * the remaining fields to match the new timeInMillis. + */ +NRTAPI(NRT_BOOL) nrt_DateTime_setTimeInMillis(nrt_DateTime * dateTime, + double timeInMillis, + nrt_Error * error); + +/*! + * Returns a DateTime object from the string with the given format. + */ +NRTAPI(nrt_DateTime *) nrt_DateTime_fromString(const char *string, + const char *format, + nrt_Error * error); + +/*! + * Destroys the DateTime object. + */ +NRTAPI(void) nrt_DateTime_destruct(nrt_DateTime **); + +/*! + * Formats a DateTime object using the given format string and output buffer. + * + * \param dateTime the DateTime object + * \param format the format string (uses the srftime format) + * \param outBuf the output buffer to write to (passed in & pre-allocated) + * \param maxSize the maximum size of the formatted output + * \param error the error object + * \return NRT_SUCCESS or NRT_FAILURE + */ +NRTAPI(NRT_BOOL) nrt_DateTime_format(const nrt_DateTime * dateTime, + const char *format, char *outBuf, + size_t maxSize, nrt_Error * error); +/*! + * + * Uses the input milliseconds since the epoch as the DateTime to format + * using the given format string and output buffer. + * + * \param millis the # of milliseconds since the epoch + * \param format the format string (uses the srftime format) + * \param outBuf the output buffer to write to (passed in & pre-allocated) + * \param maxSize the maximum size of the formatted output + * \param error the error object + * \return NRT_SUCCESS or NRT_FAILURE + */ +NRTAPI(NRT_BOOL) nrt_DateTime_formatMillis(double millis, const char *format, + char *outBuf, size_t maxSize, + nrt_Error * error); + +NRT_CXX_ENDGUARD +#endif diff --git a/modules/c/nrt/include/nrt/Debug.h b/modules/c/nrt/include/nrt/Debug.h new file mode 100644 index 000000000..0b75d8e13 --- /dev/null +++ b/modules/c/nrt/include/nrt/Debug.h @@ -0,0 +1,85 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NRT_DEBUG_H__ +#define __NRT_DEBUG_H__ + +#include "nrt/Defines.h" +#include "nrt/Types.h" +#ifdef NRT_DEBUG + +# define NRT_MEM_LOG "memory_trace" + +NRT_CXX_GUARD +/*! + * This will some space, and record that space in a file. + * The format will look like + * MALLOC + * Not threadsafe! + * + * \param file The file where the action occurred + * \param line The line where the action occurred + * \param sz The size to allocate + * \return The Pointer, or NULL on failure + */ +NRTPROT(void *) nrt_Debug_malloc(const char *file, int line, size_t sz); + +/*! + * Reallocate some space and record that space in a file. + * The format will look like + * REALLOC + * Not threadsafe! + * + * \param file The file where the action occurred + * \param line The line where the action occurred + * \param sz The sz to allocate + * \return The pointer or NULL on failure + */ +NRTPROT(void *) nrt_Debug_realloc(const char *file, int line, void *ptr, + size_t sz); + +/*! + * Free some space and record that space in a file. + * The format will look like + * FREE + * \param file The file where the action occurred + * \param line The line where the action occurred + * \param ptr The ptr to free + */ +NRTPROT(void) nrt_Debug_free(const char *file, int line, void *ptr); + +NRT_CXX_ENDGUARD +#endif + NRT_CXX_GUARD +/*! + * \fn nrt_Debug_flogf + * \brief Used for debugging. Prints only if NRT_DEBUG is defined + * + * Print to file only if NRT_DEBUG defined + * + * \param file The file to write out + * \param format Everything else + */ +NRTPROT(void) nrt_Debug_flogf(FILE * file, const char *format, ...); + +NRT_CXX_ENDGUARD +#endif diff --git a/modules/c/nrt/include/nrt/Defines.h b/modules/c/nrt/include/nrt/Defines.h new file mode 100644 index 000000000..848a9a146 --- /dev/null +++ b/modules/c/nrt/include/nrt/Defines.h @@ -0,0 +1,105 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NRT_DEFINES_H__ +#define __NRT_DEFINES_H__ + +/* The version of the NRT library */ +#define NRT_LIB_VERSION "2.6" + +#ifdef __cplusplus +# define NRT_C extern "C" +# define NRT_GUARD { +# define NRT_ENDGUARD } +# define NRT_BOOL bool +#else +# define NRT_C +# define NRT_GUARD +# define NRT_ENDGUARD +# define NRT_BOOL int +#endif + +#ifdef WIN32 +/* Negotiate the meaning of NRTAPI, NRTPROT (for public and protected) */ +# if defined(NRT_MODULE_EXPORTS) +# define NRTAPI(RT) NRT_C __declspec(dllexport) RT +# define NRTPROT(RT) NRT_C __declspec(dllexport) RT +# elif defined(NRT_MODULE_IMPORTS) +# define NRTAPI(RT) NRT_C __declspec(dllimport) RT +# define NRTPROT(RT) NRT_C __declspec(dllexport) RT +# else /* Static library */ +# define NRTAPI(RT) NRT_C RT +# define NRTPROT(RT) NRT_C RT +# endif +/* String conversion, on windows */ +# define NRT_ATO32(A) strtol(A, (char **)NULL, 10) +# define NRT_ATOU32(A) strtoul(A, (char **)NULL, 10) +# define NRT_ATOU32_BASE(A,B) strtoul(A, (char **)NULL, B) +# define NRT_ATO64(A) _atoi64(A) +# define NRT_SNPRINTF _snprintf +# define NRT_VSNPRINTF _vsnprintf +#else +/* +* NRTAPI and NRTPROT don't mean as much on Unix since they +* Don't try and mangle functions for you in C +*/ +# define NRTAPI(RT) NRT_C RT +# define NRTPROT(RT) NRT_C RT +# define NRT_ATO32(A) strtol(A, (char **)NULL, 10) +# define NRT_ATOU32(A) strtoul(A, (char **)NULL, 10) +# define NRT_ATOU32_BASE(A,B) strtoul(A, (char **)NULL, B) +# if defined(__aix__) +# define NRT_ATO64(A) strtoll(A, 0, 0) +# else +# define NRT_ATO64(A) atoll(A) +# endif +# define NRT_SNPRINTF snprintf +# define NRT_VSNPRINTF vsnprintf +#endif +/* + * This section describes a set of macros to help with + * C++ compilation. The 'extern C' set is required to + * prevent name-mangling. + * + * We also define a boolean according to the language, + * since it is obnoxious to use an int when C++ has a + * perfectly good one already. + */ + +#define NRT_CXX_GUARD NRT_C NRT_GUARD +#define NRT_CXX_ENDGUARD NRT_ENDGUARD + +/* Private declarations. */ +#define NRTPRIV(RT) static RT + +/* Negotiate the 'context' */ +#define NRT_FILE __FILE__ +#define NRT_LINE __LINE__ +#if defined(__GNUC__) +# define NRT_FUNC __PRETTY_FUNCTION__ +#elif __STDC_VERSION__ < 199901 +# define NRT_FUNC "unknown function" +#else /* Should be c99 */ +# define NRT_FUNC __func__ +#endif + +#endif diff --git a/modules/c/nrt/include/nrt/Directory.h b/modules/c/nrt/include/nrt/Directory.h new file mode 100644 index 000000000..c5f877447 --- /dev/null +++ b/modules/c/nrt/include/nrt/Directory.h @@ -0,0 +1,72 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NRT_DIRECTORY_H__ +#define __NRT_DIRECTORY_H__ + +#include "nrt/Defines.h" +#include "nrt/Types.h" +#include "nrt/Error.h" +#include "nrt/Memory.h" + +NRT_CXX_GUARD + +typedef void nrt_Directory; + +/*! + * Create a directory object. Gives back a directory object + * \param error An error to populate on failure + * \return A directory object + */ +NRTAPI(nrt_Directory *) nrt_Directory_construct(nrt_Error * error); + +/*! + * Find the first file in a directory. + * \param dir The directory object to operate on + * \param path The path to assign this directory + * \return The name of the first file in the directory + */ +NRTAPI(const char *) nrt_Directory_findFirstFile(nrt_Directory * dir, + const char *path); + +/*! + * Opens the next file in a directory. This call should be made + * after a call has been already made to findFirstFile + * \param dir The directory object to operate on + * \return The name of the next file in the directory, or NULL if none + */ +NRTAPI(const char *) nrt_Directory_findNextFile(nrt_Directory * dir); + +/*! + * Destroy the directory object in question + */ +NRTAPI(void) nrt_Directory_destruct(nrt_Directory ** dir); + +/*! + * Check if the directory exists + * \param dir The name of the directory to check + * \return 1 if exists, 0 if not exists + */ +NRTAPI(NRT_BOOL) nrt_Directory_exists(const char *dir); + +NRT_CXX_ENDGUARD +#endif diff --git a/modules/c/nrt/include/nrt/Error.h b/modules/c/nrt/include/nrt/Error.h new file mode 100644 index 000000000..57c9f1d14 --- /dev/null +++ b/modules/c/nrt/include/nrt/Error.h @@ -0,0 +1,150 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NRT_ERROR_H__ +#define __NRT_ERROR_H__ + +#include "nrt/Defines.h" +#include "nrt/Types.h" + +#define NRT_MAX_EMESSAGE 1024 +#define NRT_CTXT NRT_FILE, NRT_LINE, NRT_FUNC + +#ifdef WIN32 +# define NRT_ERRNO GetLastError() +# define NRT_STRERROR(E) strerror(E) +#else +# define NRT_ERRNO errno +# define NRT_STRERROR(E) strerror(E) +#endif + +NRT_CXX_GUARD +/* + * + * An error level can be low, medium, high, or critical. + * + */ +enum +{ + NRT_NO_ERR = 0, + NRT_ERR_MEMORY, + NRT_ERR_OPENING_FILE, + NRT_ERR_READING_FROM_FILE, + NRT_ERR_SEEKING_IN_FILE, + NRT_ERR_WRITING_TO_FILE, + NRT_ERR_STAT_FILE, + NRT_ERR_LOADING_DLL, + NRT_ERR_UNLOADING_DLL, + NRT_ERR_RETRIEVING_DLL_HOOK, + NRT_ERR_UNINITIALIZED_DLL_READ, + NRT_ERR_INVALID_PARAMETER, + NRT_ERR_INVALID_OBJECT, + NRT_ERR_INVALID_FILE, + NRT_ERR_COMPRESSION, + NRT_ERR_DECOMPRESSION, + NRT_ERR_PARSING_FILE, + NRT_ERR_INT_STACK_OVERFLOW, + NRT_ERR_UNK +}; + +/*! + * \struct nrt_Error + * \brief This structure contains nitf information + * + * The important components of an error are stored here + */ +typedef struct _NRT_Error +{ + char message[NRT_MAX_EMESSAGE + 1]; + char file[NRT_MAX_PATH + 1]; + int line; + char func[NRT_MAX_PATH + 1]; + int level; +} nrt_Error; + +/*! + * \fn nrt_Error_init + * \brief Initialize an error object (since these arent malloc'ed) + * + * This method sets up an error by initializing it with the + * context information, and the error level (which is defineds as + * one of these enum values below) and a message. + * + * \param error The error to init + * \param message The error message to init (a string) + * \param file Context info from NRT_CTXT + * \param line Context info from NRT_CTXT + * \param func Context info from NRT_CTXT (if C99) + & \param level The level of error (This is an enum value) + */ +NRTPROT(void) nrt_Error_init(nrt_Error * error, const char *message, + const char *file, int line, const char *func, + int level); + +/*! + * \fn nrt_Error_flogf + * \brief Print an existing error to a file handle + * \param error An existing error + * \param file An open file stream (could be stderr/stdout) + * \param level Not necessary [REMOVE ME] + * \param format The format string + */ +NRTAPI(void) nrt_Error_flogf(nrt_Error * error, FILE * file, int level, + const char *format, ...); + +/*! + * \fn nrt_Error_printf + * \brief Print an existing error to a file handle + * \param error An existing error + * \param file An open file stream (could be stderr/stdout) + * \param format The format string + */ +NRTAPI(void) nrt_Error_fprintf(nrt_Error * error, FILE * file, + const char *format, ...); + +/*! + * \fn nrt_Error_initf + * \brief Initialize an error using a format string. This should only be + * done by library functions. + * \param file The file nane + * \param line The line number + * \param func The function (if identifiable) + * \param level The type of error (an enum value) + * \param format A format string + */ +NRTPROT(void) nrt_Error_initf(nrt_Error * error, const char *file, int line, + const char *func, int level, const char *format, + ...); + +/*! + * \fn nrt_Error_print + * \brief Print the error to a file stream + * + * \param error The error to print out + * \param file An open file stream to write to + * \param userMessage Any user message data to be displayed + */ +NRTAPI(void) nrt_Error_print(nrt_Error * error, FILE * file, + const char *userMessage); + +NRT_CXX_ENDGUARD +#endif diff --git a/modules/c/nrt/include/nrt/HashTable.h b/modules/c/nrt/include/nrt/HashTable.h new file mode 100644 index 000000000..2735c026b --- /dev/null +++ b/modules/c/nrt/include/nrt/HashTable.h @@ -0,0 +1,264 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NRT_HASH_TABLE_H__ +#define __NRT_HASH_TABLE_H__ + +#include "nrt/Pair.h" +#include "nrt/List.h" + +NRT_CXX_GUARD +/* + * These are values for ownership. You may elect either policy. + * Here is the difference. In the hash table, the datafield is + * a pointer to an object. That object may have been allocated by + * you, or it may be static. You may wish to remove it + * yourself, or it may be told to remove it for you. + */ +enum +{ + NRT_DATA_RETAIN_OWNER = 0, NRT_DATA_ADOPT = 1 +}; + +/*! + * \struct nrt_HashTable + * \brief The hash table structure + * + * This represents a non-unique hash table structure. + */ +typedef struct _NRT_HashTable +{ + nrt_List **buckets; + int nbuckets; + int adopt; + unsigned int (*hash) (struct _NRT_HashTable *, const char *); +} nrt_HashTable; + +typedef unsigned int (*NRT_HASH_FUNCTION) (nrt_HashTable *, const char *); + +typedef int (*NRT_HASH_FUNCTOR) (nrt_HashTable *, nrt_Pair * pair, + NRT_DATA * userData, nrt_Error * error); + +/*! + * \struct nrt_HashTableIterator + * \brief This is a basic iterator object for a HashTable + */ +typedef struct _NRT_HashTableIterator +{ + nrt_HashTable *hash; /* ! The hash this is an iterator for */ + int curBucket; /* ! The current bucket */ + nrt_ListIterator listIter; /* ! The iterator for the current bucket chain */ +} nrt_HashTableIterator; + +/*! + * Constructor. This creates the hash table. + * + * \param nbuckets The size of the hash + * \param error An error to populate on failure + * \return NULL (on failure), or a pointer to the hash table + */ +NRTAPI(nrt_HashTable *) nrt_HashTable_construct(int nbuckets, + nrt_Error * error); + +/*! + * Clone this object. This is a deep copy operation. + * + * \param source The source object + * \param cloner A NRT_DATA_ITEM_CLONE function that gets called foreach + * \param error An error to populate upon failure + * \return A new object that is identical to the old + */ +NRTAPI(nrt_HashTable *) nrt_HashTable_clone(nrt_HashTable * source, + NRT_DATA_ITEM_CLONE cloner, + nrt_Error * error); + +/*! + * This function controls ownership. You may elect either policy, + * NRT_DATA_ADOPT, or NRT_DATA_RETAIN_OWNER + * Here is the difference. In the hash table, the data field is + * a pointer to an object. That object may have been allocated by + * you, or it may be static, I dont know. You may wish to remove it + * yourself, or I may be told to remove it for you. If you do not tell + * me, I will assume that you own it. + * \param ht The hash table + * \param policy The policy, either NRT_DATA_ADOPT + * or NRT_DATA_RETAIN_OWNER + */ +NRTAPI(void) nrt_HashTable_setPolicy(nrt_HashTable * ht, int policy); + +/*! + * Remove data from the hash table. Here is the removal policy: + * You ask for this object to be removed from the hash + * - We remove the pair from the hash and delete the pair associated + * with the storage + * - We give you back your data, if it exists + * - You are expected to delete the data we give you + * + * + * \note It doesn't matter if you asked us to adopt your object, if you + * remove it prematurely, you are required to delete it yourself. + * + * \param ht The hash table + * \param key The key to search for + * \return The data for deletion. If you remove it, you HAVE to delete it + * + */ +NRTAPI(NRT_DATA *) nrt_HashTable_remove(nrt_HashTable * ht, const char *key); + +/*! + * This is the default hashing function. It gets bound when + * initDefaults() is called. It is bound to the function pointer + * in the hash table + * \param ht The hash table object + * \param key The string key + */ +NRTAPI(unsigned int) __NRT_HashTable_defaultHash(nrt_HashTable * ht, const char *key); + +/*! + * The default initializer. This assigns the hash function to + * a "good default." + * \param ht The hash table + * + */ +NRTAPI(void) nrt_HashTable_initDefaults(nrt_HashTable * ht); + +/*! + * The destructor. This function is fairly complex. Here is its + * contract: + * + * - A value MUST be non-zero to be deletable + * - A non-deletable value must be zero with the exception of data + * - If there is a hash it will be deleted + * - If there is a list of lists (buckets), they will be deleted + * - If there is a list within the list, it will be traversed + * # During traversal, foreach node, each pair will be deleted + * # In the process of deleting the pair, the key will be deleted + * # At the same time, depending on the policy, the data (the value) + * MAY be deleted (if policy is NRT_DATA_ADOPT). + * + * + * + * The default behavior is to not adopt your data. You need to change this + * if you wish for me to delete your data. + * + * \param ht A pointer to a hash (ptr), so we can null it + * + */ +NRTAPI(void) nrt_HashTable_destruct(nrt_HashTable ** ht); + +/*! + * Check to see whether such a key exists in the hash table + * \param ht The hash to search + * \param key The key to lookup + * \return 1 if such a key exists, 0 if it does not + */ +NRTAPI(NRT_BOOL) nrt_HashTable_exists(nrt_HashTable * ht, const char *key); + +/*! + * This is a debug tool to see what's in our hash + * \param ht The hash to print + */ +NRTAPI(void) nrt_HashTable_print(nrt_HashTable * ht); + +/*! + * Foreach item in the hash table, do something (slow) + * \param ht The hash table + * \param fn The function to perform + * \param userData Optional user-defined data to pass to the functor + * \param error An error if one occurred + * \return Status + */ +NRTAPI(NRT_BOOL) nrt_HashTable_foreach(nrt_HashTable * ht, NRT_HASH_FUNCTOR fn, + NRT_DATA * userData, nrt_Error * error); + +/*! + * Insert this key/data pair into the hash table + * \param ht The hash table to insert to + * \param key The key to insert under + * \param data The data to insert into the second value of the pair + * \param error An error if one occurred + * \return 1 if success, 0 if failure + */ +NRTAPI(NRT_BOOL) nrt_HashTable_insert(nrt_HashTable * ht, const char *key, + NRT_DATA * data, nrt_Error * error); + +/*! + * Retrieve some key/value pair from the hash table + * \param ht The hash table to retrieve from + * \param key The key to retrieve by + * \return The chain link associated with the pair + */ +NRTAPI(nrt_Pair *) nrt_HashTable_find(nrt_HashTable * ht, const char *key); + +/*! + * Check to see if two iterators point at the same thing + * + * \param it1 Iterator 1 + * \param it2 Iterator 2 + * \return 1 if they are equal, 0 if not + */ +NRTAPI(NRT_BOOL) nrt_HashTableIterator_equals(nrt_HashTableIterator * it1, + nrt_HashTableIterator * it2); + +/*! + * Check to see if two iterators are not pointing at the same thing + * + * \param it1 Iterator 1 + * \param it2 Iterator 2 + * \return 1 if they are not equal, 0 if so + */ +NRTAPI(NRT_BOOL) nrt_HashTableIterator_notEqualTo(nrt_HashTableIterator * it1, + nrt_HashTableIterator * it2); + +/*! + * Return an iterator to the head of the chain + * + * \param chain The chain to search + * \return An iterator to the head of the chain + */ +NRTAPI(nrt_HashTableIterator) nrt_HashTable_begin(nrt_HashTable * ht); + +/*! + * Get an iterator to the tail of the chain + * + * \param this_chain + * \return Iterator to chain tail + */ +NRTAPI(nrt_HashTableIterator) nrt_HashTable_end(nrt_HashTable * ht); + +/*! + * Increment the iterator. Eventually, this will point at NULL. + * + * \param this_iter Iterator to increment + * + */ +NRTAPI(void) nrt_HashTableIterator_increment(nrt_HashTableIterator * iter); + +/*! + * Get the pair (key, value) this iterator points to + * + * \return The data + */ +NRTAPI(nrt_Pair *) nrt_HashTableIterator_get(nrt_HashTableIterator * iter); + +NRT_CXX_ENDGUARD +#endif diff --git a/modules/c/nrt/include/nrt/IOHandle.h b/modules/c/nrt/include/nrt/IOHandle.h new file mode 100644 index 000000000..54f665ceb --- /dev/null +++ b/modules/c/nrt/include/nrt/IOHandle.h @@ -0,0 +1,132 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, + * see . + * + */ + +#ifndef __NRT_IO_HANDLE_H__ +#define __NRT_IO_HANDLE_H__ + +#include "nrt/System.h" + +# define NRT_IO_SUCCESS(I) ((I) >= 0) + +/* How many times should we try to read until we declare the IOHandle dead. Use a timeout later. */ +#ifndef NITF_MAX_READ_ATTEMPTS +#define NRT_MAX_READ_ATTEMPTS 100 +#endif + +NRT_CXX_GUARD +/*! + * Create an IO handle. If the file is set to create, + * the permissions will be built into the create: + * \see System.h + * + * \param fname The file name + * \param access The access: valid values include the or'ing of: + * NRT_READONLY + * NRT_WRITEONLY + * NRT_READWRITE + * \param + * \param error The populated error, only if NRT_INVALID_HANDLE() + * \return The fresh handle. Test this with NRT_INVALID_HANDLE() + */ +NRTAPI(nrt_IOHandle) nrt_IOHandle_create(const char *fname, + nrt_AccessFlags access, + nrt_CreationFlags creation, + nrt_Error * error); + +/*! + * Read from the IO handle. This function is guaranteed to return + * after having read the requisite number of bytes or fail out. + * Check its return value against zero or NRT_FAILURE. + * + * \param handle The handle to read from + * \param buf The buffer to read into + * \param size The number of bytes to read + * \param error Populated if function returns 0 + * \return 1 on success and 0 otherwise + */ +NRTAPI(NRT_BOOL) nrt_IOHandle_read(nrt_IOHandle handle, char *buf, size_t size, + nrt_Error * error); + +/*! + * Write to the IO handle. This function attempts to write to the IO handle + * until it has written the requisite number of bytes (specified as the size + * parameter). Upon failure, it returns NRT_FAILURE and the error is set. + * + * \param handle The handle to write from + * \param buf The buffer to write from + * \param size The number of bytes to write + * \param error The error, only if !NRT_IO_SUCCESS() + * \return NRT_SUCCESS if the method succeeds, NRT_FAILURE on failure. + */ +NRTAPI(NRT_BOOL) nrt_IOHandle_write(nrt_IOHandle handle, const char *buf, + size_t size, nrt_Error * error); + +/*! + * Seek into the handle at this point. Basically + * has the same usage as lseek(). If whence is SEEK_SET, the seek + * pointer is to offset bytes. If SEEK_CUR, start at the + * current offset and add offset argument. If SEEK_END, the seek + * is added to the size of the file. On failure, should return a value + * that may be checked with NRT_IO_SUCCESS() + * + * \param handle The handle to use + * \param offset The seek offset + * \param whence Starting at (SEEK_SET, SEEK_CUR, SEEK_END) + * \param error The error, if !NRT_IO_SUCCESS() + * \return The offset from the beginning to the current position + */ +NRTAPI(nrt_Off) nrt_IOHandle_seek(nrt_IOHandle handle, nrt_Off offset, + int whence, nrt_Error * error); + +/*! + * Tell the location that the handle is pointing to. On failure, + * this returns a value that may be checked with the NRT_IO_SUCCESS() + * macro. + * + * \param handle The io handle + * \param error The error to populate if there is a problem + * \return The offset + */ +NRTAPI(nrt_Off) nrt_IOHandle_tell(nrt_IOHandle handle, nrt_Error * error); + +/*! + * Get the size of the handle (how big is the file). + * As with the other methods, this function should return a value + * that is testable with NRT_IO_SUCCESS(). + * + * + * \param handle The handle to determine the size of + * \param error A populated error if something goes wrong + * \return The size of the file + */ +NRTAPI(nrt_Off) nrt_IOHandle_getSize(nrt_IOHandle handle, nrt_Error * error); + +/*! + * Close the IO handle. + * + * \param handle The handle to close + * \return void + */ +NRTAPI(void) nrt_IOHandle_close(nrt_IOHandle handle); + +NRT_CXX_ENDGUARD +#endif diff --git a/modules/c/nrt/include/nrt/IOInterface.h b/modules/c/nrt/include/nrt/IOInterface.h new file mode 100644 index 000000000..f65907bad --- /dev/null +++ b/modules/c/nrt/include/nrt/IOInterface.h @@ -0,0 +1,135 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, + * see . + * + */ + +#ifndef __NRT_IO_INTERFACE_H__ +#define __NRT_IO_INTERFACE_H__ + +/* Default implementation */ +#include "nrt/IOHandle.h" + +NRT_CXX_GUARD + +typedef NRT_BOOL(*NRT_IO_INTERFACE_READ) (NRT_DATA *, char *, size_t, + nrt_Error *); +typedef NRT_BOOL(*NRT_IO_INTERFACE_WRITE) (NRT_DATA *, const char *, size_t, + nrt_Error *); +typedef NRT_BOOL(*NRT_IO_INTERFACE_CAN_SEEK) (NRT_DATA *, nrt_Error *); +typedef nrt_Off(*NRT_IO_INTERFACE_SEEK) (NRT_DATA *, nrt_Off, int, nrt_Error *); +typedef nrt_Off(*NRT_IO_INTERFACE_TELL) (NRT_DATA *, nrt_Error *); +typedef nrt_Off(*NRT_IO_INTERFACE_GET_SIZE) (NRT_DATA *, nrt_Error *); +typedef int (*NRT_IO_INTERFACE_GET_MODE) (NRT_DATA *, nrt_Error *); +typedef NRT_BOOL(*NRT_IO_INTERFACE_CLOSE) (NRT_DATA *, nrt_Error *); +typedef void (*NRT_IO_INTERFACE_DESTRUCT) (NRT_DATA *); + +typedef struct _NRT_IIOInterface +{ + NRT_IO_INTERFACE_READ read; + NRT_IO_INTERFACE_WRITE write; + NRT_IO_INTERFACE_CAN_SEEK canSeek; + NRT_IO_INTERFACE_SEEK seek; + NRT_IO_INTERFACE_TELL tell; + NRT_IO_INTERFACE_GET_SIZE getSize; + NRT_IO_INTERFACE_GET_MODE getMode; + NRT_IO_INTERFACE_CLOSE close; + NRT_IO_INTERFACE_DESTRUCT destruct; +} nrt_IIOInterface; + +typedef struct _NRT_IOInterface +{ + NRT_DATA *data; + nrt_IIOInterface *iface; +} nrt_IOInterface; + +/** + * Reads data from the interface + */ +NRTAPI(NRT_BOOL) nrt_IOInterface_read(nrt_IOInterface *, char *buf, size_t size, + nrt_Error * error); + +/** + * Writes data to the interface + */ +NRTAPI(NRT_BOOL) nrt_IOInterface_write(nrt_IOInterface * io, const char *buf, + size_t size, nrt_Error * error); + +/** + * Returns whether the interface is seekable + */ +NRTAPI(NRT_BOOL) nrt_IOInterface_canSeek(nrt_IOInterface * io, nrt_Error *); + +/** + * Seeks to the offset specified, given the provided seek scenario + */ +NRTAPI(nrt_Off) nrt_IOInterface_seek(nrt_IOInterface * io, nrt_Off offset, + int whence, nrt_Error * error); + +/** + * Returns the current offset + */ +NRTAPI(nrt_Off) nrt_IOInterface_tell(nrt_IOInterface * io, nrt_Error * error); + +/** + * Returns the current size + */ +NRTAPI(nrt_Off) nrt_IOInterface_getSize(nrt_IOInterface * io, + nrt_Error * error); + +/** + * Returns the access mode (NRT_ACCESS_READONLY, NRT_ACCESS_WRITEONLY, + * NRT_ACCESS_READWRITE) + */ +NRTAPI(int) nrt_IOInterface_getMode(nrt_IOInterface * io, nrt_Error * error); + +/** + * Closes the interface + */ +NRTAPI(NRT_BOOL) nrt_IOInterface_close(nrt_IOInterface * io, nrt_Error * error); + +/** + * Destroys the interface and cleans up any owned resources + */ +NRTAPI(void) nrt_IOInterface_destruct(nrt_IOInterface ** io); + +/** + * Creates an IOInterface that wraps an IOHandle. + */ +NRTAPI(nrt_IOInterface *) nrt_IOHandleAdapter_construct(nrt_IOHandle handle, + int accessMode, + nrt_Error * error); + +/** + * Creates an IOInterface that wraps an IOHandle. + */ +NRTAPI(nrt_IOInterface *) nrt_IOHandleAdapter_open(const char *fname, + int accessFlags, + int creationFlags, + nrt_Error * error); + +/** + * Creats an IOInterface that wraps a buffer + */ +NRTAPI(nrt_IOInterface *) nrt_BufferAdapter_construct(char *buf, size_t size, + NRT_BOOL ownBuf, + nrt_Error * error); + +NRT_CXX_ENDGUARD +#endif diff --git a/modules/c/nrt/include/nrt/IntStack.h b/modules/c/nrt/include/nrt/IntStack.h new file mode 100644 index 000000000..daeaecfc3 --- /dev/null +++ b/modules/c/nrt/include/nrt/IntStack.h @@ -0,0 +1,54 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NRT_INT_STACK_H__ +#define __NRT_INT_STACK_H__ + +#include "nrt/System.h" + +#define NRT_INT_STACK_DEPTH 10 + +NRT_CXX_GUARD + +typedef struct _protected_nrt_IntStack +{ + int sp; + int st[NRT_INT_STACK_DEPTH]; +} nrt_IntStack; + +NRTPROT(nrt_IntStack *) nrt_IntStack_construct(nrt_Error * error); + +NRTPROT(nrt_IntStack *) nrt_IntStack_clone(nrt_IntStack * stack, + nrt_Error * error); + +NRTPROT(void) nrt_IntStack_destruct(nrt_IntStack ** stack); + +NRTPROT(int) nrt_IntStack_top(nrt_IntStack * stack, nrt_Error * error); + +NRTPROT(int) nrt_IntStack_push(nrt_IntStack * stack, int n, nrt_Error * error); + +NRTPROT(int) nrt_IntStack_pop(nrt_IntStack * stack, nrt_Error * error); + +NRTPROT(int) nrt_IntStack_depth(nrt_IntStack * stack, nrt_Error * error); + +NRT_CXX_ENDGUARD +#endif diff --git a/modules/c/nrt/include/nrt/List.h b/modules/c/nrt/include/nrt/List.h new file mode 100644 index 000000000..38228a8c1 --- /dev/null +++ b/modules/c/nrt/include/nrt/List.h @@ -0,0 +1,319 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; + * If not, see . + * + */ + +#ifndef __NRT_LIST_H__ +#define __NRT_LIST_H__ +/*! + * \file + * \brief Contains OO-like linked-list data structure for pairs + * + * This file contains an OO-like API for a linked list API of + * nrt_Pair objects (the first item is a string, the second is a + * generic pointer. + * + * The structures are modeled on the C++ Standard Template Library. + */ +#include "nrt/System.h" + +NRT_CXX_GUARD +/*! + * \struct nrt_ListNode + * \brief Node in a nrt_List + * + * This object provides the base for a chain in a hash. + * It is a doubly-linked list with pair data (the first of which + * is copied, the second of which is not). + */ +typedef struct _NRT_ListNode +{ + /* ! Pointer to the next structure */ + struct _NRT_ListNode *next; + /* ! Pointer to the previous structure */ + struct _NRT_ListNode *prev; + /* ! The data */ + NRT_DATA *data; +} nrt_ListNode; + +typedef NRT_DATA *(*NRT_DATA_ITEM_CLONE) (NRT_DATA *, nrt_Error *); + +/*! + * \struct nrt_ListIterator + * \brief This is a basic iterator object for a chain + * + * This object is a basic iterator for a nrt_List object. + * It is modeled on the C++ Standard Template Library + */ +typedef struct _NRT_ListIterator +{ + /* ! Pointer to the current node */ + nrt_ListNode *current; + +} nrt_ListIterator; + +/*! + * \struct nrt_List + * \brief A linked list of nrt_Pair items + * + * This object is the controller for the nrt_ListNode nodes. + * It contains a pointer to the first and last items in its set. + */ +typedef struct _NRT_List +{ + /* ! A pointer to the beginning node */ + nrt_ListNode *first; + /* ! A pointer to the final node */ + nrt_ListNode *last; + +} nrt_List; + +/*! + * Construct a new node. This node will be attached to its + * previous and next nodes, if any. The data in the nrt_Pair + * will be the data that is assigned. + * + * \param prev The previous node (the one in front of this one) + * \param next The next node (the one after this one) + * \param data The data to insert into the list + * \param error An error to populate on fatal issue + * \return The list node, or NULL if a problem occurred + */ +NRTAPI(nrt_ListNode *) nrt_ListNode_construct(nrt_ListNode * prev, + nrt_ListNode * next, + NRT_DATA * data, + nrt_Error * error); + +/*! + * Destroy the current chain link, and NULL set it + * We are not deleting the data, so I hope you did. + * \param this_node Node to destroy + */ +NRTAPI(void) nrt_ListNode_destruct(nrt_ListNode ** this_node); + +/*! + * Is our chain empty? Since our list ends with a NULL + * link, we simply check to see if the first link is NULL. + * + * \param this_chain The chain to check + * \return 1 if empty, 0 if contains items + */ +NRTAPI(NRT_BOOL) nrt_List_isEmpty(nrt_List * this_chain); + +/*! + * Push something onto the front of our chain. Note, as usual + * we REFUSE to allocate your data for you. If you need a copy, make one + * up front. + * + * \param this_chain The chain to push information onto + * \param data The data to push to the front + * \param error An error if one occurred + */ +NRTAPI(NRT_BOOL) nrt_List_pushFront(nrt_List * this_chain, NRT_DATA * data, + nrt_Error * error); + +/*! + * Push something onto the back of our chain + * \param this_chain The chain to push information onto + * \param data The data to push onto the back + * \param error The error if one occurred + */ +NRTAPI(NRT_BOOL) nrt_List_pushBack(nrt_List * this_chain, NRT_DATA * data, + nrt_Error * error); + +/*! + * Pop the node off the front and return it. + * We check the first item to see if it exists. If it does, + * Then we fill in, and return the value. + * + * \param this_chain The chain to pop from + * \return The link we popped off + */ +NRTAPI(NRT_DATA *) nrt_List_popFront(nrt_List * this_chain); + +/*! + * Pop the node off the back and return it. + * We check the first item to see if it exists. If it does, + * Then we fill in, and return the value + * + * \param this_chain The chain to pop from + * \return The link we popped off + */ +NRTAPI(NRT_DATA *) nrt_List_popBack(nrt_List * this_chain); + +/*! + * Construct our chain and null-initialize the first and last pointers + * \param error An error to populate on failure + * \return The chain, or NULL upon failure + */ +NRTAPI(nrt_List *) nrt_List_construct(nrt_Error * error); + +/*! + * Clone this object. This is a deep copy operation. + * + * \param source The source object + * \param cloner A NRT_DATA_ITEM_CLONE function that gets called foreach + * \param error An error to populate upon failure + * \return A new object that is identical to the old + */ +NRTAPI(nrt_List *) nrt_List_clone(nrt_List * source, NRT_DATA_ITEM_CLONE cloner, + nrt_Error * error); + +/*! + * Delete the chain (from the back). This means we destruct each node. + * This also means that you need to free all of the data + * in your list, prior to us + * + * \param this_chain The chain to delete + */ +NRTAPI(void) nrt_List_destruct(nrt_List ** this_chain); + +/*! + * Return an iterator to the head of the chain + * + * \param chain The chain to search + * \return An iterator to the head of the chain + */ +NRTAPI(nrt_ListIterator) nrt_List_begin(nrt_List * chain); + +/*! + * Return an iterator to the position in the chain + * specified by the index i. + * + * \param chain The chain to search + * \param i the index + * \return An iterator to the index of the chain, as specified by i + */ +NRTAPI(nrt_ListIterator) nrt_List_at(nrt_List * chain, int i); + +/*! + * Check to see if two iterators point at the same thing + * + * \param it1 Iterator 1 + * \param it2 Iterator 2 + * \return 1 if they are equal, 0 if not + */ +NRTAPI(NRT_BOOL) nrt_ListIterator_equals(nrt_ListIterator * it1, + nrt_ListIterator * it2); + +/*! + * Check to see if two iterators are not pointing at the same thing + * + * \param it1 Iterator 1 + * \param it2 Iterator 2 + * \return 1 if they are not equal, 0 if so + */ +NRTAPI(NRT_BOOL) nrt_ListIterator_notEqualTo(nrt_ListIterator * it1, + nrt_ListIterator * it2); + +/*! + * Get an iterator to the tail of the chain + * + * \param this_chain + * \return Iterator to chain tail + */ +NRTAPI(nrt_ListIterator) nrt_List_end(nrt_List * this_chain); + +/*! + * Insert data into the chain BEFORE the iterator, and make the iterator + * point at the new node. + * + *
+ *

    + *
  1. If the iterator is pointing to NULL, we will insert into the back of + * this list
  2. + *
  3. If the iterator is pointing to the beginning, we will insert into the + * front
  4. + * + *
  5. If the iterator is pointing at something else, we will insert after + * the iterator (same case, in practice as pointing to the beginning)
  6. + *
+ * + * \param chain The chain + * \param iter The iterator to insert before + * \param data This is a pointer assignment, not a data copy + * \param error An error to populate on failure + * + * \return 1 on success, 0 on failure + */ +NRTAPI(NRT_BOOL) nrt_List_insert(nrt_List * chain, nrt_ListIterator iter, + NRT_DATA * data, nrt_Error * error); + +/*! + * Remove the data from an arbitrary point in the list. + * This WILL NOT delete the data, but it will make sure + * that we have successfully updated the chain. The + * iterator is moved to the value that the current node pointed to + * (the next value). + * + * \param chain The list to remove from + * \param where Where to remove, this will be updated to the NEXT position + * \return We dont know how to delete YOUR object, so return it + */ +NRTAPI(NRT_DATA *) nrt_List_remove(nrt_List * chain, nrt_ListIterator * where); + +/*! + * Moves the data located at oldIndex to newIndex. + * + * \param chain The source list + * \param oldIndex the index of the data item to move + * \param newIndex the index where the data item will be moved to + * \return NRT_SUCCESS on success, or NRT_FAILURE + */ +NRTAPI(NRT_BOOL) nrt_List_move(nrt_List * chain, nrt_Uint32 oldIndex, + nrt_Uint32 newIndex, nrt_Error * error); + +/*! + * Return the size of the list + * + * \param list The list to check + * \return size of the list + */ +NRTAPI(nrt_Uint32) nrt_List_size(nrt_List * list); + +/*! + * Return the element at the specified position in the list + * + * \param list The list + * \param index The index + * \param index The index + * \param error An error to populate on failure, if the index is out of bounds + * \return the data at the specified position + */ +NRTAPI(NRT_DATA *) nrt_List_get(nrt_List * list, int index, nrt_Error * error); + +/*! + * Increment the iterator. Eventually, this will point at NULL. + * + * \param this_iter Iterator to increment + * + */ +NRTAPI(void) nrt_ListIterator_increment(nrt_ListIterator * this_iter); + +/*! + * Get the data at this iterators pointer + * + * \return The data + * + */ +NRTAPI(NRT_DATA *) nrt_ListIterator_get(nrt_ListIterator * this_iter); + +NRT_CXX_ENDGUARD +#endif diff --git a/modules/c/nrt/include/nrt/Memory.h b/modules/c/nrt/include/nrt/Memory.h new file mode 100644 index 000000000..bb9174c2b --- /dev/null +++ b/modules/c/nrt/include/nrt/Memory.h @@ -0,0 +1,44 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NRT_MEMORY_H__ +#define __NRT_MEMORY_H__ + +/* + * \file + * Memory is a very simple allocation tracker. When NRT_DEBUG + * is on, NRT_MALLOC and NRT_FREE to book-keeping. When it is not, + * they turn into malloc() and free() + */ + +#ifdef NRT_DEBUG +# include "nrt/Debug.h" +# define NRT_MALLOC(P) nrt_Debug_malloc(__FILE__, __LINE__, P) +# define NRT_REALLOC(P, S) nrt_Debug_realloc(__FILE__, __LINE__, P, S) +# define NRT_FREE(P) nrt_Debug_free(__FILE__, __LINE__, P) +#else +# define NRT_MALLOC malloc +# define NRT_REALLOC realloc +# define NRT_FREE free +#endif + +#endif diff --git a/modules/c/nrt/include/nrt/Pair.h b/modules/c/nrt/include/nrt/Pair.h new file mode 100644 index 000000000..4917b8751 --- /dev/null +++ b/modules/c/nrt/include/nrt/Pair.h @@ -0,0 +1,59 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NRT_PAIR_H__ +#define __NRT_PAIR_H__ + +#include "nrt/System.h" + +NRT_CXX_GUARD +/*! + * \struct nrt_Pair + * \brief This is an object containing the data and the key + * + * The nrt_Pair is an object similar to a std::pair. + * + */ + +#ifndef __NRT_SYNC_H__ +#define __NRT_SYNC_H__ + +#include "nrt/Defines.h" +#include "nrt/Types.h" +#include "nrt/Memory.h" + +NRT_CXX_GUARD +#if defined(WIN32) +typedef LPCRITICAL_SECTION nrt_Mutex; +#elif defined(__sgi) +# include +# define NRT_MUTEX_INIT 0 +typedef int nrt_Mutex; +#else +# include +# define NRT_MUTEX_INIT PTHREAD_MUTEX_INITIALIZER +typedef pthread_mutex_t nrt_Mutex; +#endif + +NRTPROT(void) nrt_Mutex_lock(nrt_Mutex * m); +NRTPROT(void) nrt_Mutex_unlock(nrt_Mutex * m); +NRTPROT(void) nrt_Mutex_init(nrt_Mutex * m); +NRTPROT(void) nrt_Mutex_delete(nrt_Mutex * m); + +NRT_CXX_ENDGUARD +#endif diff --git a/modules/c/nrt/include/nrt/System.h b/modules/c/nrt/include/nrt/System.h new file mode 100644 index 000000000..4a6495412 --- /dev/null +++ b/modules/c/nrt/include/nrt/System.h @@ -0,0 +1,40 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NRT_SYSTEM_H__ +#define __NRT_SYSTEM_H__ + +#include "nrt/Defines.h" +#include "nrt/Types.h" +#include "nrt/Error.h" +#include "nrt/Memory.h" +#include "nrt/DLL.h" +#include "nrt/Sync.h" +#include "nrt/Directory.h" +#include "nrt/IOHandle.h" + +NRTPROT(nrt_Uint16) nrt_System_swap16(nrt_Uint16 ins); +NRTPROT(nrt_Uint32) nrt_System_swap32(nrt_Uint32 inl); +NRTPROT(nrt_Uint64) nrt_System_swap64c(nrt_Uint64 inl); +NRTPROT(nrt_Uint64) nrt_System_swap64(nrt_Uint64 inl); + +#endif diff --git a/modules/c/nrt/include/nrt/Tree.h b/modules/c/nrt/include/nrt/Tree.h new file mode 100644 index 000000000..5e6f7bfed --- /dev/null +++ b/modules/c/nrt/include/nrt/Tree.h @@ -0,0 +1,194 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; + * If not, see . + * + */ + +#ifndef __NRT_TREE_H__ +#define __NRT_TREE_H__ + +#include "nrt/System.h" +#include "nrt/List.h" + +NRT_CXX_GUARD +/*! + * \struct nrt_TreeNode + * \brief A Tree Node in a nrt_Tree + * + * This object provides the base node for a tree + * data structure (not to be confused with a TRE, + * or Tagged Record Extension). Trees may be useful + * for certain kinds of parsing, and it may also at + * some point become the default storage for TREs + * themselves. Since a tree isnt really a flat data + * structure, traversal functions may be more appropriate + * than our typical + * + */ +typedef struct _NRT_TreeNode +{ + + struct _NRT_TreeNode *parent; + + /* ! The child nodes List */ + nrt_List *children; + + /* ! The data */ + NRT_DATA *data; +} nrt_TreeNode; + +typedef struct _NRT_Tree +{ + /* ! The root node */ + nrt_TreeNode *root; + +} nrt_Tree; + +/*! + * Construct a new (detached) TreeNode. This function will assign + * its user data to the tree node, and will only return error if + * memory cannot be allocated for the TreeNode (or its child list). + * The user is assumed to be responsible for the data associated with + * the node + * + * \param data The data to encapsulate + * \param parent Parent (can be NULL if this is the root) + * \param error The error to return + * + */ +NRTAPI(nrt_TreeNode *) nrt_TreeNode_construct(NRT_DATA * data, + nrt_Error * error); + +/*! + * Destroy the current node and NULL set it. We are not responsible + * for deleting the data in the node, it is up to the user to delete. + * + * \param node The node + */ +NRTAPI(void) nrt_TreeNode_destruct(nrt_TreeNode ** node); + +/*! + * Add a node to our children. The child will be appended to the NITF + * list. + * + * \param node Our node + * \param child The node to add + * \param error The error + * \return NRT_SUCCESS on success, NRT_FAILURE on failure + * + */ +NRTAPI(NRT_BOOL) nrt_TreeNode_addChild(nrt_TreeNode * node, + nrt_TreeNode * child, nrt_Error * error); + +/*! + * Return if this tree node has children. This is slightly easier than + * going directly to the underlying list. + * + * \param node The node + * \return 1 if we have children, 0, if not. + */ +NRTAPI(NRT_BOOL) nrt_TreeNode_hasChildren(nrt_TreeNode * node); + +/*! + * Remove this child from the list. We will remove our list element + * associated with this node from our Tree, if it exists. + * + * Note, if there are multiple of the same node in this tree, + * we arent currently accounting for that, so if you knew that + * you had it, you would have to call this function repeatedly, + * e.g., while (nrt_TreeNode_remove(tree, node)); + */ +NRTAPI(NRT_BOOL) nrt_TreeNode_removeChild(nrt_TreeNode * node, + nrt_TreeNode * child); + +/*! + * Clone our TreeNode into a new one. We will need a clone function + * to tell us how to clone our NRT_DATA + */ +NRTAPI(nrt_TreeNode *) nrt_TreeNode_clone(nrt_TreeNode * source, + NRT_DATA_ITEM_CLONE cloner, + nrt_Error * error); + +/*! + * Get ourselves a top-level data structure that can be used to control + * an integral tree. It is okay to leave our root element as NULL. + * We will simply not initialize the root + * + * \param An error. + * + */ +NRTAPI(nrt_Tree *) nrt_Tree_construct(nrt_TreeNode * root, nrt_Error * error); + +/*! + * Destroy our tree + * \param tree The tree to destruct + */ +NRTAPI(void) nrt_Tree_destruct(nrt_Tree ** tree); + +typedef enum _NRT_Traversal +{ + NRT_PRE_ORDER = 0, + NRT_POST_ORDER + /* We are not a binary tree, so no inorder traversal */ +} nrt_Traversal; + +/*! + * This is a traversal function. When you call nrt_Tree_walk() + * you will give it the user data that is necessary to run this + * + * The node will be handed to this function by the traversal + * The function returns true or false if it succeeded or failed. + * If it failed, you should set the nrt_Error*. On failure, + * we will short-circuit the walk method. + * + */ +typedef NRT_BOOL(*NRT_TREE_TRAVERSER) (nrt_TreeNode *, NRT_DATA * userData, + int depth, nrt_Error *); + +/*! + * Walk our tree using one of the traversal methods specified. + * Our function will stop if any traversal fails. That means + * that the NRT_TREE_TRAVERSER is returning 1 as NRT_SUCCESS + * and 0 as NRT_FAILURE. On NRT_FAILURE, we expect your onNode() + * to have returned us an error that we will hand back to the application + * + */ +NRTAPI(NRT_BOOL) nrt_Tree_walk(nrt_Tree * tree, NRT_TREE_TRAVERSER onNode, + int traversalOrder, NRT_DATA * userData, + nrt_Error * error); + +/*! + * Only providing this because we have to. It looks identical to the + * List clone function. + * + * \param source The tree to clone + * \param cloner the clone function for the NRT_DATA in the element + * \param error An error to populate on failure + * + * \return A Tree that is the clone of source + */ +NRTAPI(nrt_Tree *) nrt_Tree_clone(nrt_Tree * source, NRT_DATA_ITEM_CLONE cloner, + nrt_Error * error); + +/* + * There are lots of other tree-type functions that I will ignore + * for now, but that would be useful, including sub-cloning, etc. + */ +NRT_CXX_ENDGUARD +#endif diff --git a/modules/c/nrt/include/nrt/Types.h b/modules/c/nrt/include/nrt/Types.h new file mode 100644 index 000000000..d1d084b5f --- /dev/null +++ b/modules/c/nrt/include/nrt/Types.h @@ -0,0 +1,207 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __NRT_TYPES_H__ +#define __NRT_TYPES_H__ + +# include +# include +# include +# include +# include +# include +# include +# include +# include + +#ifdef WIN32 +# include + +/* Types are defined for windows here */ +typedef unsigned char nrt_Uint8; +typedef unsigned __int16 nrt_Uint16; +typedef unsigned __int32 nrt_Uint32; +typedef unsigned __int64 nrt_Uint64; + +typedef signed char nrt_Int8; +typedef __int16 nrt_Int16; +typedef __int32 nrt_Int32; +typedef __int64 nrt_Int64; +typedef HANDLE nrt_IOHandle; +typedef HINSTANCE NRT_NATIVE_DLL; +typedef FARPROC NRT_DLL_FUNCTION_PTR; +typedef DWORD nrt_AccessFlags; +typedef DWORD nrt_CreationFlags; +/* Determine the maximum file path length */ +# define NRT_MAX_PATH MAX_PATH + +/* use nrt_Off instead of off_t, since on Windows we want nrt_Int64 used */ +typedef nrt_Int64 nrt_Off; + +/* IO macros */ +# define NRT_INVALID_HANDLE_VALUE INVALID_HANDLE_VALUE +# define NRT_INVALID_HANDLE(I) ((I) == NRT_INVALID_HANDLE_VALUE) +# define NRT_SEEK_CUR FILE_CURRENT +# define NRT_SEEK_SET FILE_BEGIN +# define NRT_SEEK_END FILE_END +# define NRT_CREATE OPEN_ALWAYS +# define NRT_OPEN_EXISTING OPEN_EXISTING +# define NRT_TRUNCATE OPEN_EXISTING +# define NRT_ACCESS_READONLY GENERIC_READ +# define NRT_ACCESS_WRITEONLY GENERIC_WRITE +# define NRT_ACCESS_READWRITE GENERIC_READ|GENERIC_WRITE + +/* type suffixes */ +# define NRT_INT64(x) x##i64 + +#else +/* +* Here, we define the basic libraries needed by +* all compilers (the non-platform specific code) +* +*/ + +# include +# include +# include +# include +# include +# include +# include + +/* Typedefs on Unix are a different ball game */ +typedef uint8_t nrt_Uint8; +typedef uint16_t nrt_Uint16; +typedef uint32_t nrt_Uint32; +typedef uint64_t nrt_Uint64; + +typedef int8_t nrt_Int8; +typedef int16_t nrt_Int16; +typedef int32_t nrt_Int32; +typedef int64_t nrt_Int64; +typedef int nrt_IOHandle; +typedef off_t nrt_Off; + +typedef void *NRT_DLL_FUNCTION_PTR; +typedef void *NRT_NATIVE_DLL; +typedef int nrt_AccessFlags; +typedef int nrt_CreationFlags; +/* +* Under Unix, we want to provide default permissions. +* Some are nice enough to default to 0666, others just +* burn you, so we make it explicit +*/ +# define NRT_DEFAULT_PERM 0644 +# define NRT_INVALID_HANDLE_VALUE -1 +# define NRT_INVALID_HANDLE(I) ((I) == NRT_INVALID_HANDLE_VALUE) +# define NRT_SEEK_CUR SEEK_CUR +# define NRT_SEEK_SET SEEK_SET +# define NRT_SEEK_END SEEK_END +# define NRT_CREATE O_CREAT +# define NRT_TRUNCATE O_TRUNC +# define NRT_OPEN_EXISTING 0 +# define NRT_ACCESS_READONLY O_RDONLY +# define NRT_ACCESS_WRITEONLY O_WRONLY +# define NRT_ACCESS_READWRITE O_RDWR + +/* type suffixes */ +# define NRT_INT64(x) x##LL + +# if defined(HAVE_SYS_TIME_H) +# include +# endif + +/* +* On most systems, this gets included in limits.h, but sometimes its not +* there, so we make one up. I figure we can easily get 1k on the stack, +* so if its not there, it gets set to that. +*/ +# if defined(MAXPATHLEN) +# define NRT_MAX_PATH MAXPATHLEN +# else +# define NRT_MAX_PATH 1024 +# endif +#endif + +#define NRT_SUCCESS (1) +#define NRT_FAILURE (0) +#define NRT_TRUE (1) +#define NRT_FALSE (0) + +typedef enum _nrt_CornersType +{ + NRT_CORNERS_UNKNOWN = -1, + NRT_CORNERS_UTM, + NRT_CORNERS_UTM_UPS_S, + NRT_CORNERS_UTM_UPS_N, + NRT_CORNERS_GEO, + NRT_CORNERS_DECIMAL +} nrt_CornersType; + +/* + * Finally, we determine what kind of system you + * are using, and come up with our own swap routines. + * This is to avoid the nasty mess that comes with + * (Unix actually) the non-standard socket include locations, + * and to avoid including sockets just to swap bytes (Ugh). + */ + +/* these functions are accessed if needed via the nrt_ntohs + and nrt_ntohl macros defined in System.h */ + +NRTPROT(nrt_Uint16) nrt_System_swap16(nrt_Uint16 ins); +NRTPROT(nrt_Uint32) nrt_System_swap32(nrt_Uint32 inl); +NRTPROT(nrt_Uint64) nrt_System_swap64(nrt_Uint64 inl); +NRTPROT(nrt_Uint64) nrt_System_swap64c(nrt_Uint64 inl); + +/* Configure says we are big-endian */ +#if defined(__LITTLE_ENDIAN__) || !defined(WORDS_BIGENDIAN) + +# define NRT_NTOHS(x) nrt_System_swap16 (x) +# define NRT_HTONS(x) nrt_System_swap16 (x) + +# define NRT_NTOHL(x) nrt_System_swap32 (x) +# define NRT_HTONL(x) nrt_System_swap32 (x) + +# define NRT_HTONLL(x) nrt_System_swap64(x) +# define NRT_NTOHLL(x) nrt_System_swap64(x) + +# define NRT_HTONLC(x) nrt_System_swap64c(x) +# define NRT_NTOHLC(x) nrt_System_swap64c(x) + +# else + +# define NRT_NTOHS(x) (x) +# define NRT_HTONS(x) (x) + +# define NRT_NTOHL(x) (x) +# define NRT_HTONL(x) (x) + +# define NRT_HTONLL(x) (x) +# define NRT_NTOHLL(x) (x) + +# define NRT_HTONLC(x) (x) +# define NRT_NTOHLC(x) (X) + +# endif +typedef void NRT_DATA; +#endif diff --git a/modules/c/nrt/include/nrt/Utils.h b/modules/c/nrt/include/nrt/Utils.h new file mode 100644 index 000000000..4f7242fa0 --- /dev/null +++ b/modules/c/nrt/include/nrt/Utils.h @@ -0,0 +1,177 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; + * If not, see . + * + */ + +#ifndef __NRT_UTILS_H__ +#define __NRT_UTILS_H__ + +#include "nrt/System.h" +#include "nrt/List.h" + +NRT_CXX_GUARD +/*! + * Splits a string apart, delimited by spaces. This does not use strtok since + * it is not thread safe.) + * \param str null-terminated string + * \param max the maximum # of parts to split into (0 = split all) + */ +NRTAPI(nrt_List *) nrt_Utils_splitString(char *str, unsigned int max, + nrt_Error * error); + +NRTAPI(NRT_BOOL) nrt_Utils_isNumeric(char *str); + +NRTAPI(NRT_BOOL) nrt_Utils_isAlpha(char *str); + +/** + * Returns 1 if the input string is either null, empty (strlen == 0), or + * if every character is a whitespace char. + */ +NRTAPI(NRT_BOOL) nrt_Utils_isBlank(char *str); + +NRTAPI(void) nrt_Utils_trimString(char *str); + +/*! + * Replace the oldValue with the newValue within this string + * + */ +NRTPROT(void) nrt_Utils_replace(char *str, char oldValue, char newValue); + +/*! + * Return the base name for the fullName, up until the + * extension is encountered. Both base and fullName should + * have at least NRT_MAX_PATH number of elements. + * + * \param base A user supplied base name target + * \param fullName The source string + * \param extension The extension name + */ +NRTAPI(void) nrt_Utils_baseName(char *base, const char *fullName, + const char *extension); + +/*! + * Take in a decimal degree format string and convert it into + * a double. The string will be of the format +-ddd.dd or +-dd.dd. + * + * \todo This function can be expanded to handle arbitrary + * size conversions. It is TBD whether this is desirable, since the + * IGEOLO itself is very strict about what is allowed + * + */ +NRTAPI(NRT_BOOL) nrt_Utils_parseDecimalString(char* d, double *decimal, + nrt_Error * error); + +NRTAPI(double) nrt_Utils_getCurrentTimeMillis(); + +NRTAPI(int) nrt_Utils_strncasecmp(char *s1, char *s2, size_t n); + +/*! + * Convert a double representing decimal degrees into 3 integers, + * one for degrees, one for minutes, and one for seconds. + * + * The function returns these values through the passed in parameters. + * parameters may not be NULL + * + * \param decimal An existing decimal degree + * \param degrees [output] The degrees as an integer + * \param minutes [output] The minutes as an integer + * \param seconds [output] The seconds as an integer + */ +NRTAPI(void) nrt_Utils_decimalToGeographic(double decimal, int *degrees, + int *minutes, double *seconds); + +/*! + * Convert the geographic coordinates (i.e., DMS) into decimal + * degrees as a double. + * + * \param degrees geographic degrees + * \param minutes geographic minutes + * \param seconds geographic seconds + */ +NRTAPI(double) nrt_Utils_geographicToDecimal(int degrees, int minutes, + double seconds); + +/*! + * Take in a degree of DMS format and convert it into integers + * The string will be of the format dddmmss[NSEW] or ddmmss[NSEW] + * Blank values are accepted (per NRT 2500C) and converted to 0s. + * + * Any other string will produce an error object with code + * NRT_ERR_INVALID_PARAMETER. + * + * \param dms The string + * \param degrees [output] The degrees as an integer + * \param minutes [output] The minutes as an integer + * \param seconds [output] The seconds as an integer + * + */ +NRTAPI(NRT_BOOL) nrt_Utils_parseGeographicString(char *dms, int *degrees, + int *minutes, double *seconds, + nrt_Error * error); + +/*! + * Turn the geographic value into a string. You must have a buffer + * with 7 elements to hand in to this function, otherwise you will + * have memory corruption. + */ +NRTPROT(void) nrt_Utils_geographicLatToCharArray(int degrees, int minutes, + double seconds, char *buffer7); + +/*! + * Turn the geographic value into a string. You must have a buffer + * with 7 elements to hand in to this function, otherwise you will + * have memory corruption. + */ +NRTPROT(void) nrt_Utils_geographicLonToCharArray(int degrees, int minutes, + double seconds, char *buffer8); + +/*! + * Turn the decimal value into a string +-dd.ddd. You must have a buffer + * with 7 elements to hand in to this function, otherwise you will + * have memory corruption. + */ +NRTPROT(void) nrt_Utils_decimalLatToCharArray(double decimal, char *buffer7); + +/*! + * Turn the decimal value into a string +-ddd.ddd. You must have a buffer + * with 7 elements to hand in to this function, otherwise you will + * have memory corruption. + */ +NRTPROT(void) nrt_Utils_decimalLonToCharArray(double decimal, char *buffer8); + +NRTPROT(void) nrt_Utils_decimalLatToGeoCharArray(double decimal, char *buffer7); + +/*! + * Turn the decimal value into a string +-ddd.ddd. You must have a buffer + * with 7 elements to hand in to this function, otherwise you will + * have memory corruption. + */ +NRTPROT(void) nrt_Utils_decimalLonToGeoCharArray(double decimal, char *buffer8); + +/*! + * Convert the corners type to a string. If for some reason, the type + * is not known, return it as ' ', which is the only other valid NRT + * value. + * + */ +NRTAPI(char) nrt_Utils_cornersTypeAsCoordRep(nrt_CornersType type); + +NRT_CXX_ENDGUARD +#endif diff --git a/modules/c/nrt/source/DLLUnix.c b/modules/c/nrt/source/DLLUnix.c new file mode 100644 index 000000000..bdc10cdfd --- /dev/null +++ b/modules/c/nrt/source/DLLUnix.c @@ -0,0 +1,126 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#if !defined(WIN32) + +#include "nrt/DLL.h" + +NRTAPI(nrt_DLL *) nrt_DLL_construct(nrt_Error * error) +{ + nrt_DLL *dll = (nrt_DLL *) NRT_MALLOC(sizeof(nrt_DLL)); + if (!dll) + { + nrt_Error_init(error, NRT_STRERROR(NRT_ERRNO), NRT_CTXT, + NRT_ERR_MEMORY); + + } + dll->libname = NULL; + dll->lib = NULL; + return dll; +} + +NRTAPI(void) nrt_DLL_destruct(nrt_DLL ** dll) +{ + nrt_Error error; + if (*dll) + { + /* destroy the lib */ + nrt_DLL_unload((*dll), &error); + if ((*dll)->libname) + { + NRT_FREE((*dll)->libname); + (*dll)->libname = NULL; + } + NRT_FREE(*dll); + *dll = NULL; + } +} + +NRTAPI(NRT_BOOL) nrt_DLL_isValid(nrt_DLL * dll) +{ + return (dll->lib != (NRT_NATIVE_DLL) NULL); +} + +NRTAPI(NRT_BOOL) nrt_DLL_load(nrt_DLL * dll, const char *libname, + nrt_Error * error) +{ + dll->libname = (char *) NRT_MALLOC(strlen(libname) + 1); + if (!dll->libname) + { + nrt_Error_init(error, NRT_STRERROR(NRT_ERRNO), NRT_CTXT, + NRT_ERR_MEMORY); + return NRT_FAILURE; + } + strcpy(dll->libname, libname); + dll->lib = dlopen(libname, RTLD_LAZY); + if (!dll->lib) + { + nrt_Error_init(error, dlerror(), NRT_CTXT, NRT_ERR_LOADING_DLL); + NRT_FREE(dll->libname); + dll->libname = NULL; + return NRT_FAILURE; + } + + return NRT_SUCCESS; +} + +NRTAPI(NRT_BOOL) nrt_DLL_unload(nrt_DLL * dll, nrt_Error * error) +{ + if (dll->lib) + { + assert(dll->libname); + NRT_FREE(dll->libname); + dll->libname = NULL; + + if (dlclose(dll->lib) != 0) + { + nrt_Error_init(error, dlerror(), NRT_CTXT, NRT_ERR_UNLOADING_DLL); + return NRT_FAILURE; + } + dll->lib = NULL; + } + return NRT_SUCCESS; +} + +NRTAPI(NRT_DLL_FUNCTION_PTR) nrt_DLL_retrieve(nrt_DLL * dll, + const char *function, + nrt_Error * error) +{ + if (dll->lib) + { + + NRT_DLL_FUNCTION_PTR ptr = dlsym(dll->lib, function); + if (ptr == (NRT_DLL_FUNCTION_PTR) NULL) + { + /* Problem if you couldnt produce the function */ + nrt_Error_init(error, dlerror(), NRT_CTXT, + NRT_ERR_RETRIEVING_DLL_HOOK); + } + return ptr; + + } + + /* You shouldnt be calling it if it didnt load */ + nrt_Error_init(error, dlerror(), NRT_CTXT, NRT_ERR_UNINITIALIZED_DLL_READ); + return (NRT_DLL_FUNCTION_PTR) NULL; +} +#endif diff --git a/modules/c/nrt/source/DLLWin32.c b/modules/c/nrt/source/DLLWin32.c new file mode 100644 index 000000000..0cb71cb58 --- /dev/null +++ b/modules/c/nrt/source/DLLWin32.c @@ -0,0 +1,135 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nrt/DLL.h" + +#if defined(WIN32) + +NRTAPI(nrt_DLL *) nrt_DLL_construct(nrt_Error * error) +{ + nrt_DLL *dll = (nrt_DLL *) NRT_MALLOC(sizeof(nrt_DLL)); + if (!dll) + { + nrt_Error_init(error, "Failed to alloc DLL", NRT_CTXT, NRT_ERR_MEMORY); + + } + dll->libname = NULL; + dll->lib = NULL; + return dll; +} + +NRTAPI(void) nrt_DLL_destruct(nrt_DLL ** dll) +{ + nrt_Error error; + if (*dll) + { + nrt_DLL_unload((*dll), &error); + if (*dll) + { + if ((*dll)->libname) + { + NRT_FREE((*dll)->libname); + (*dll)->libname = NULL; + } + NRT_FREE(*dll); + *dll = NULL; + } + } +} + +NRTAPI(NRT_BOOL) nrt_DLL_isValid(nrt_DLL * dll) +{ + return (dll->lib != (NRT_NATIVE_DLL) NULL); +} + +NRTAPI(NRT_BOOL) nrt_DLL_load(nrt_DLL * dll, const char *libname, + nrt_Error * error) +{ + dll->libname = (char *) NRT_MALLOC(strlen(libname) + 1); + if (!dll->libname) + { + nrt_Error_init(error, NRT_STRERROR(NRT_ERRNO), NRT_CTXT, + NRT_ERR_MEMORY); + return NRT_FAILURE; + } + + strcpy(dll->libname, libname); + dll->lib = LoadLibrary(dll->libname); + if (!dll->lib) + { + nrt_Error_initf(error, NRT_CTXT, NRT_ERR_LOADING_DLL, + "Failed to load library [%s]", dll->libname); + NRT_FREE(dll->libname); + dll->libname = NULL; + return NRT_FAILURE; + } + return NRT_SUCCESS; +} + +NRTAPI(NRT_BOOL) nrt_DLL_unload(nrt_DLL * dll, nrt_Error * error) +{ + if (dll->lib) + { + assert(dll->libname); + NRT_FREE(dll->libname); + dll->libname = NULL; + + if (!FreeLibrary(dll->lib)) + { + nrt_Error_initf(error, NRT_CTXT, NRT_ERR_UNLOADING_DLL, + "Failed to unload library [%s]", dll->libname); + + return NRT_FAILURE; + } + dll->lib = NULL; + } + return 1; +} + +NRTAPI(NRT_DLL_FUNCTION_PTR) nrt_DLL_retrieve(nrt_DLL * dll, + const char *function, + nrt_Error * error) +{ + /* Make sure we actually have a dll */ + if (dll->lib) + { + NRT_DLL_FUNCTION_PTR ptr = + (NRT_DLL_FUNCTION_PTR) GetProcAddress(dll->lib, + function); + /* Now check the resultant value */ + if (ptr == NULL) + { + /* Problem if you couldnt produce the function */ + nrt_Error_initf(error, NRT_CTXT, NRT_ERR_RETRIEVING_DLL_HOOK, + "Failed to get function [%s] from dll [%s]", + function, dll->libname); + + } + return ptr; + } + + nrt_Error_initf(error, NRT_CTXT, NRT_ERR_UNINITIALIZED_DLL_READ, + "Failed to retrieve function [%s] -- DLL appears to be uninitialized", + function); + return (NRT_DLL_FUNCTION_PTR) NULL; +} +#endif diff --git a/modules/c/nrt/source/DateTime.c b/modules/c/nrt/source/DateTime.c new file mode 100644 index 000000000..ffd5bcc93 --- /dev/null +++ b/modules/c/nrt/source/DateTime.c @@ -0,0 +1,885 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include +#include +#include + +#include "nrt/DateTime.h" + +#define NRT_YEAR0 1900 +#define NRT_EPOCH_YEAR 1970 /* EPOCH = Jan 1 1970 00:00:00 */ + +/* At the end of each month, the total number of days so far in the year. + * Index 0 is for non-leap years, index 1 is for leap years */ +const int NRT_CUMULATIVE_DAYS_PER_MONTH[2][12] = +{ + {31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365}, + {31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366} +}; + +/* The number of days in a year. Index 0 is for non-leap years, index 1 is + * for leap years */ +const int NRT_DAYS_PER_YEAR[2] = {365, 366}; + +/* Returns the appropriate index into NRT_CUMULATIVE_DAYS_PER_MONTH based on + * whether 'year' is a leap year or not */ +NRTPRIV(int) nrtYearIndex(int year) +{ + return (!(year % 4) && ((year % 100) || !(year % 400))); +} + +/* Returns the # of full days so far in the year + * 'month' and 'dayOfMonth' are 1-based + * So, nrtGetNumFullDaysInYearSoFar(2000, 1, 1) = 0 + * nrtGetNumFullDaysInYearSoFar(2000, 1, 2) = 1 + * nrtGetNumFullDaysInYearSoFar(2000, 2, 1) = 31 + */ +NRTPRIV(int) nrtGetNumFullDaysInYearSoFar(int year, int month, int dayOfMonth) +{ + /* The number of days for all the full months so far */ + int numFullDays = (month > 1) ? + NRT_CUMULATIVE_DAYS_PER_MONTH[nrtYearIndex(year)][month - 2] : + 0; + + /* The number of full days in this month so far */ + numFullDays += dayOfMonth - 1; + return numFullDays; +} + +NRTPRIV(char *) _NRT_strptime(const char *buf, const char *fmt, struct tm *tm, + double *millis); + +NRTAPI(nrt_DateTime *) nrt_DateTime_now(nrt_Error * error) +{ + return nrt_DateTime_fromMillis(nrt_Utils_getCurrentTimeMillis(), error); +} + +NRTAPI(nrt_DateTime *) nrt_DateTime_fromMillis(double millis, nrt_Error * error) +{ + nrt_DateTime *dt = NULL; + + dt = (nrt_DateTime *) NRT_MALLOC(sizeof(nrt_DateTime)); + if (!dt) + { + nrt_Error_init(error, NRT_STRERROR(NRT_ERRNO), NRT_CTXT, + NRT_ERR_MEMORY); + return NULL; + } + + nrt_DateTime_setTimeInMillis(dt, millis, error); + + return dt; +} + +NRTPRIV(NRT_BOOL) nrt_DateTime_updateMillis(nrt_DateTime* dateTime, + nrt_Error* error) +{ + long numDaysThisYear; + long numDaysSinceEpoch; + int year; + + /* Silence compiler warnings about unused variables */ + (void)error; + + /* Sanity checks. If things aren't valid, just set timeInMillis to 0. */ + /* TODO: Not sure if we should error out instead. The advantage of this + * approach is if a caller is gradually setting fields, it won't + * error out, and once they have set all 6 fields, the struct will + * be in a valid state */ + if (dateTime->second < 0.0 || dateTime->second >= 60.0 || + dateTime->minute > 59 || + dateTime->hour > 23 || + dateTime->dayOfMonth < 1 || dateTime->dayOfMonth > 31 || + dateTime->month < 1 || dateTime->month > 12 || + dateTime->year < 1970 || dateTime->year > 2037) + { + dateTime->timeInMillis = 0.0; + dateTime->dayOfYear = dateTime->dayOfWeek = 0; + return NRT_SUCCESS; + } + + /* Essentially we are implementing a simplified variant of mktime() here. + * Implementation loosely based on + * http://www.raspberryginger.com/jbailey/minix/html/mktime_8c-source.html + * The problem with mktime() is that it expects local time and we are in + * GMT. Note that we can't just call mktime(), then look at the + * difference between localtime() and gmtime() and offset the result by + * that amount because this approach can't reliably take daylight savings + * time into account. Another option would be to trick mktime() by + * setting the TZ environment variable to UTC, but this wouldn't be + * reentrant. + * It is very unfortunate that there's no POSIX standard function similar + * to mktime() that allows you to pass in the timezone you want. + * */ + + /* Count up the # of days this year */ + numDaysThisYear = nrtGetNumFullDaysInYearSoFar(dateTime->year, + dateTime->month, + dateTime->dayOfMonth); + + /* Count up the # of days for all the years prior to this one + * TODO: This could be implemented more efficiently - see reference + * implementation above. */ + numDaysSinceEpoch = 0; + for (year = NRT_EPOCH_YEAR; year < dateTime->year; ++year) + { + numDaysSinceEpoch += NRT_DAYS_PER_YEAR[nrtYearIndex(year)]; + } + numDaysSinceEpoch += numDaysThisYear; + + dateTime->timeInMillis = + (dateTime->second + + dateTime->minute * 60.0 + + dateTime->hour * (60.0 * 60.0) + + numDaysSinceEpoch * (60.0 * 60.0 * 24.0)) * 1000.0; + + dateTime->dayOfYear = numDaysThisYear + 1; + + /* January 1, 1970 was a Thursday (5) */ + dateTime->dayOfWeek = (numDaysSinceEpoch + 5) % 7; + + return NRT_SUCCESS; +} + +NRTAPI(NRT_BOOL) nrt_DateTime_setYear(nrt_DateTime * dateTime, int year, + nrt_Error * error) +{ + dateTime->year = year; + return nrt_DateTime_updateMillis(dateTime, error); +} + +NRTAPI(NRT_BOOL) nrt_DateTime_setMonth(nrt_DateTime * dateTime, int month, + nrt_Error * error) +{ + dateTime->month = month; + return nrt_DateTime_updateMillis(dateTime, error); +} + +NRTAPI(NRT_BOOL) nrt_DateTime_setDayOfMonth(nrt_DateTime * dateTime, + int dayOfMonth, nrt_Error * error) +{ + dateTime->dayOfMonth = dayOfMonth; + return nrt_DateTime_updateMillis(dateTime, error); +} + +NRTAPI(NRT_BOOL) nrt_DateTime_setHour(nrt_DateTime * dateTime, int hour, + nrt_Error * error) +{ + dateTime->hour = hour; + return nrt_DateTime_updateMillis(dateTime, error); +} + +NRTAPI(NRT_BOOL) nrt_DateTime_setMinute(nrt_DateTime * dateTime, int minute, + nrt_Error * error) +{ + dateTime->minute = minute; + return nrt_DateTime_updateMillis(dateTime, error); +} + +NRTAPI(NRT_BOOL) nrt_DateTime_setSecond(nrt_DateTime * dateTime, double second, + nrt_Error * error) +{ + dateTime->second = second; + return nrt_DateTime_updateMillis(dateTime, error); +} + +NRTAPI(NRT_BOOL) nrt_DateTime_setTimeInMillis(nrt_DateTime * dateTime, + double timeInMillis, + nrt_Error * error) +{ + time_t timeInSeconds; + struct tm t; + + /* Silence compiler warnings about unused variables */ + (void)error; + + timeInSeconds = (time_t) (timeInMillis / 1000); + t = *gmtime(&timeInSeconds); + + dateTime->timeInMillis = timeInMillis; + + /* this is the year since 1900 */ + dateTime->year = t.tm_year + 1900; + + /* 0-based so add 1 */ + dateTime->month = t.tm_mon + 1; + dateTime->dayOfMonth = t.tm_mday; + dateTime->dayOfWeek = t.tm_wday + 1; + dateTime->dayOfYear = t.tm_yday + 1; + dateTime->hour = t.tm_hour; + dateTime->minute = t.tm_min; + dateTime->second = t.tm_sec + (timeInMillis / 1000.0 - timeInSeconds); + + return NRT_SUCCESS; +} + +NRTAPI(nrt_DateTime *) nrt_DateTime_fromString(const char *string, + const char *format, + nrt_Error * error) +{ + struct tm t; + nrt_DateTime *dateTime = NULL; + double millis = 0.0; + + /* NOTE: _NRT_strptime() does not use the tm_isdst flag at all. */ + t.tm_isdst = -1; + + if (!_NRT_strptime(string, format, &t, &millis)) + { + nrt_Error_initf(error, NRT_CTXT, NRT_ERR_INVALID_OBJECT, + "Unknown error caused by the call to strptime with string [%s] and format string [%s]", + string, format); + return NULL; + } + + /* Create a DateTime object */ + dateTime = (nrt_DateTime *) NRT_MALLOC(sizeof(nrt_DateTime)); + if (!dateTime) + { + nrt_Error_init(error, NRT_STRERROR(NRT_ERRNO), NRT_CTXT, + NRT_ERR_MEMORY); + return NULL; + } + + /* Initialize it from the tm struct + * TODO: Update _NRT_strptime() to just use a DateTime directly */ + dateTime->year = t.tm_year + 1900; + + /* 0-based so add 1 */ + dateTime->month = t.tm_mon + 1; + dateTime->dayOfMonth = t.tm_mday; + dateTime->dayOfWeek = t.tm_wday + 1; + dateTime->dayOfYear = t.tm_yday + 1; + dateTime->hour = t.tm_hour; + dateTime->minute = t.tm_min; + dateTime->second = t.tm_sec + millis / 1000.0; + + /* Compute the # of milliseconds */ + if (!nrt_DateTime_updateMillis(dateTime, error)) + { + NRT_FREE(dateTime); + return NULL; + } + + return dateTime; +} + +NRTAPI(void) nrt_DateTime_destruct(nrt_DateTime ** dt) +{ + if (*dt) + { + NRT_FREE(*dt); + *dt = NULL; + } +} + +NRTAPI(NRT_BOOL) nrt_DateTime_format(const nrt_DateTime * dateTime, + const char *format, char *outBuf, + size_t maxSize, nrt_Error * error) +{ + return nrt_DateTime_formatMillis(dateTime->timeInMillis, format, outBuf, + maxSize, error); +} + +NRTAPI(NRT_BOOL) nrt_DateTime_formatMillis(double millis, const char *format, + char *outBuf, size_t maxSize, + nrt_Error * error) +{ + time_t timeInSeconds; + double fractSeconds; + struct tm t; + char *newFmtString = NULL; + const char *endString = NULL; + size_t begStringLen = 0; + size_t formatLength; + size_t startIndex = 0; + size_t i, j; + NRT_BOOL found = 0; + + timeInSeconds = (time_t) (millis / 1000); + t = *gmtime(&timeInSeconds); + fractSeconds = (millis / 1000.0) - timeInSeconds; + + /* Search for "%...S" string */ + formatLength = strlen(format); + for (i = 0; i < formatLength && !found; ++i) + { + if (format[i] == '%') + { + startIndex = i; + for (j = startIndex + 1; j < formatLength; ++j) + { + if (format[j] == '%') + { + break; + } + + if (format[j] == 'S') + { + found = 1; + formatLength = j - startIndex + 1; + begStringLen = startIndex; + endString = format + j + 1; + } + } + } + } + + /* If we found a "%...S" string, parse it */ + /* to find out how many decimal places to use */ + if (found) + { + int decimalPlaces = 0; + + /* Figure out how many decimal places we need... */ + for (i = startIndex + 1; i < startIndex + (formatLength - 1); ++i) + { + if (format[i] == '.') + { + /* The digits that follow should be */ + /* the number of decimal places */ + sscanf(format + i + 1, "%d", &decimalPlaces); + } + } + + if (decimalPlaces > 0) + { + char buf[256]; + size_t newFmtLen = 0; + size_t bufIdx = 0; + size_t endStringLen = endString ? strlen(endString) : 0; + + newFmtLen = begStringLen + 1; + newFmtString = (char *) NRT_MALLOC(newFmtLen); + if (!newFmtString) + { + nrt_Error_init(error, NRT_STRERROR(NRT_ERRNO), NRT_CTXT, + NRT_ERR_MEMORY); + goto CATCH_ERROR; + } + memset(newFmtString, 0, newFmtLen); + + if (begStringLen > 0) + { + /* do the first part of the format */ + strncpy(newFmtString, format, begStringLen); + + if (strftime(outBuf, maxSize, newFmtString, &t) == 0) + { + nrt_Error_initf(error, NRT_CTXT, NRT_ERR_INVALID_OBJECT, + "Unknown error caused by the call to strftime with format string: [%s]", + format); + goto CATCH_ERROR; + } + bufIdx = strlen(outBuf); + } + + /* do the seconds - separately */ + memset(buf, 0, 256); + if (strftime(buf, 256, "%S", &t) == 0) + { + nrt_Error_initf(error, NRT_CTXT, NRT_ERR_INVALID_OBJECT, + "Unknown error caused by the call to strftime with format string: [%s]", + format); + goto CATCH_ERROR; + } + + if (strlen(buf) + bufIdx + 1 > maxSize) + { + nrt_Error_initf(error, NRT_CTXT, NRT_ERR_INVALID_OBJECT, + "Format string will cause buffer to overflow: [%s]", + format); + goto CATCH_ERROR; + } + + /* tack it on the end */ + strcpy(outBuf + bufIdx, buf); + bufIdx = strlen(outBuf); + + memset(buf, 0, 256); + NRT_SNPRINTF(buf, 256, "%.*f", decimalPlaces, fractSeconds); + + if (strlen(buf) + bufIdx + 1 > maxSize) + { + nrt_Error_initf(error, NRT_CTXT, NRT_ERR_INVALID_OBJECT, + "Format string will cause buffer to overflow: [%s]", + format); + goto CATCH_ERROR; + } + + /* tack on the fractional seconds - spare the leading 0 */ + strcpy(outBuf + bufIdx, buf + 1); + bufIdx = strlen(outBuf); + + if (endStringLen > 0) + { + /* tack on the end part */ + memset(buf, 0, 256); + if (strftime(buf, 256, endString, &t) == 0) + { + nrt_Error_initf(error, NRT_CTXT, NRT_ERR_INVALID_OBJECT, + "Unknown error caused by the call to strftime with format string: [%s]", + format); + goto CATCH_ERROR; + } + + if (strlen(buf) + bufIdx + 1 > maxSize) + { + nrt_Error_initf(error, NRT_CTXT, NRT_ERR_INVALID_OBJECT, + "Format string will cause buffer to overflow: [%s]", + format); + goto CATCH_ERROR; + } + strcpy(outBuf + bufIdx, buf); + } + } + } + + if (newFmtString == NULL) + { + if (strftime + (outBuf, maxSize, newFmtString != NULL ? newFmtString : format, + &t) == 0) + { + nrt_Error_initf(error, NRT_CTXT, NRT_ERR_INVALID_OBJECT, + "Unknown error caused by the call to strftime with format string: [%s]", + newFmtString != NULL ? newFmtString : format); + goto CATCH_ERROR; + } + } + else + NRT_FREE(newFmtString); + + return NRT_SUCCESS; + + CATCH_ERROR: + if (newFmtString) + NRT_FREE(newFmtString); + + return NRT_FAILURE; +} + +/* http://social.msdn.microsoft.com/forums/en-US/vcgeneral/thread/25a654f9-b6b6-490a-8f36-c87483bb36b7 */ + +/* + * We do not implement alternate representations. However, we always + * check whether a given modifier is allowed for a certain conversion. + */ +#define ALT_E 0x01 +#define ALT_O 0x02 +/* #define LEGAL_ALT(x) { if (alt_format & ~(x)) return (0); } */ +#define LEGAL_ALT(x) { ; } +#define TM_YEAR_BASE NRT_YEAR0 + +static const char *day[7] = { "Sunday", "Monday", "Tuesday", "Wednesday", + "Thursday", "Friday", "Saturday" +}; +static const char *abday[7] = + { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; +static const char *mon[12] = { "January", "February", "March", "April", "May", + "June", "July", "August", "September", + "October", "November", "December" +}; + +static const char *abmon[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" +}; +static const char *am_pm[2] = { "AM", "PM" }; + +NRTPRIV(int) _NRT_convNum(const char **, int *, int, int); + +NRTPRIV(char *) _NRT_strptime(const char *buf, const char *fmt, struct tm *tm, + double *millis) +{ + char c; + const char *bp; + size_t len = 0; + int alt_format, i, split_year = 0; + + bp = buf; + *millis = 0.0; + + /* init */ + tm->tm_sec = tm->tm_min = tm->tm_hour = tm->tm_mday = tm->tm_mon = + tm->tm_year = tm->tm_wday = tm->tm_yday = 0; + /* tm->tm_isdst = lt.tm_isdst; */ + + while ((c = *fmt) != '\0') + { + /* Clear `alternate' modifier prior to new conversion. */ + alt_format = 0; + + /* Eat up white-space. */ + if (isspace(c)) + { + while (isspace(*bp)) + bp++; + + fmt++; + continue; + } + + if ((c = *fmt++) != '%') + goto literal; + + again:switch (c = *fmt++) + { + case '%': /* "%%" is converted to "%". */ + literal: + if (c != *bp++) + return NULL; + break; + + /* + * "Alternative" modifiers. Just set the appropriate flag + * and start over again. + */ + case 'E': /* "%E?" alternative conversion modifier. */ + LEGAL_ALT(0); + alt_format |= ALT_E; + goto again; + + case 'O': /* "%O?" alternative conversion modifier. */ + LEGAL_ALT(0); + alt_format |= ALT_O; + goto again; + + /* + * "Complex" conversion rules, implemented through recursion. + */ + case 'c': /* Date and time, using the locale's format. */ + LEGAL_ALT(ALT_E); + bp = _NRT_strptime(bp, "%x %X", tm, millis); + if (!bp) + return NULL; + break; + + case 'D': /* The date as "%m/%d/%y". */ + LEGAL_ALT(0); + bp = _NRT_strptime(bp, "%m/%d/%y", tm, millis); + if (!bp) + return NULL; + break; + + case 'R': /* The time as "%H:%M". */ + LEGAL_ALT(0); + bp = _NRT_strptime(bp, "%H:%M", tm, millis); + if (!bp) + return NULL; + break; + + case 'r': /* The time in 12-hour clock representation. */ + LEGAL_ALT(0); + bp = _NRT_strptime(bp, "%I:%M:%S %p", tm, millis); + if (!bp) + return NULL; + break; + + case 'T': /* The time as "%H:%M:%S". */ + LEGAL_ALT(0); + bp = _NRT_strptime(bp, "%H:%M:%S", tm, millis); + if (!bp) + return NULL; + break; + + case 'X': /* The time, using the locale's format. */ + LEGAL_ALT(ALT_E); + bp = _NRT_strptime(bp, "%H:%M:%S", tm, millis); + if (!bp) + return NULL; + break; + + case 'x': /* The date, using the locale's format. */ + LEGAL_ALT(ALT_E); + bp = _NRT_strptime(bp, "%m/%d/%y", tm, millis); + if (!bp) + return NULL; + break; + + /* + * "Elementary" conversion rules. + */ + case 'A': /* The day of week, using the locale's form. */ + case 'a': + LEGAL_ALT(0); + for (i = 0; i < 7; i++) + { + /* Full name. */ + len = strlen(day[i]); + if (nrt_Utils_strncasecmp((char *) (day[i]), (char *) bp, len) + == 0) + break; + + /* Abbreviated name. */ + len = strlen(abday[i]); + if (nrt_Utils_strncasecmp((char *) (abday[i]), (char *) bp, len) + == 0) + break; + } + + /* Nothing matched. */ + if (i == 7) + return NULL; + + tm->tm_wday = i; + bp += len; + break; + + case 'B': /* The month, using the locale's form. */ + case 'b': + case 'h': + LEGAL_ALT(0); + for (i = 0; i < 12; i++) + { + /* Full name. */ + len = strlen(mon[i]); + if (nrt_Utils_strncasecmp((char *) (mon[i]), (char *) bp, len) + == 0) + break; + + /* Abbreviated name. */ + len = strlen(abmon[i]); + if (nrt_Utils_strncasecmp((char *) (abmon[i]), (char *) bp, len) + == 0) + break; + } + + /* Nothing matched. */ + if (i == 12) + return NULL; + + tm->tm_mon = i; + bp += len; + break; + + case 'C': /* The century number. */ + LEGAL_ALT(ALT_E); + if (!(_NRT_convNum(&bp, &i, 0, 99))) + return NULL; + + if (split_year) + { + tm->tm_year = (tm->tm_year % 100) + (i * 100); + } + else + { + tm->tm_year = i * 100; + split_year = 1; + } + break; + + case 'd': /* The day of month. */ + case 'e': + LEGAL_ALT(ALT_O); + if (!(_NRT_convNum(&bp, &tm->tm_mday, 1, 31))) + return NULL; + break; + + case 'k': /* The hour (24-hour clock representation). */ + LEGAL_ALT(0); + /* FALLTHROUGH */ + case 'H': + LEGAL_ALT(ALT_O); + if (!(_NRT_convNum(&bp, &tm->tm_hour, 0, 23))) + return NULL; + break; + + case 'l': /* The hour (12-hour clock representation). */ + LEGAL_ALT(0); + /* FALLTHROUGH */ + case 'I': + LEGAL_ALT(ALT_O); + if (!(_NRT_convNum(&bp, &tm->tm_hour, 1, 12))) + return NULL; + if (tm->tm_hour == 12) + tm->tm_hour = 0; + break; + + case 'j': /* The day of year. */ + LEGAL_ALT(0); + if (!(_NRT_convNum(&bp, &i, 1, 366))) + return NULL; + tm->tm_yday = i - 1; + break; + + case 'M': /* The minute. */ + LEGAL_ALT(ALT_O); + if (!(_NRT_convNum(&bp, &tm->tm_min, 0, 59))) + return NULL; + break; + + case 'm': /* The month. */ + LEGAL_ALT(ALT_O); + if (!(_NRT_convNum(&bp, &i, 1, 12))) + return NULL; + tm->tm_mon = i - 1; + break; + +/* case 'p': The locale's equivalent of AM/PM. + LEGAL_ALT(0); + AM? + if (strcasecmp(am_pm[0], bp) == 0) + { + if (tm->tm_hour > 11) + return NULL; + + bp += strlen(am_pm[0]); + break; + } + PM? + else if (strcasecmp(am_pm[1], bp) == 0) + { + if (tm->tm_hour > 11) + return NULL; + + tm->tm_hour += 12; + bp += strlen(am_pm[1]); + break; + } + + Nothing matched. + return NULL;*/ + + case 'S': /* The seconds. */ + LEGAL_ALT(ALT_O); + if (!(_NRT_convNum(&bp, &tm->tm_sec, 0, 61))) + return NULL; + + /* Determine if the next character is a decimal... */ + if (*bp == '.') + { + int decimalPlaces = 0; + /* Get the fractional seconds value */ + bp++; + while (*bp >= '0' && *bp <= '9') + { + double num = (double) (*bp++ - '0'); + decimalPlaces++; + + switch (decimalPlaces) + { + case 1: + num *= 100; + break; + case 2: + num *= 10; + break; + case 3: + break; + default: + for (i = 0; i < decimalPlaces - 3; ++i) + num /= 10.0; + break; + } + *millis += num; + } + } + break; + + case 'U': /* The week of year, beginning on sunday. */ + case 'W': /* The week of year, beginning on monday. */ + LEGAL_ALT(ALT_O); + /* + * XXX This is bogus, as we can not assume any valid + * information present in the tm structure at this + * point to calculate a real value, so just check the + * range for now. + */ + if (!(_NRT_convNum(&bp, &i, 0, 53))) + return NULL; + break; + + case 'w': /* The day of week, beginning on sunday. */ + LEGAL_ALT(ALT_O); + if (!(_NRT_convNum(&bp, &tm->tm_wday, 0, 6))) + return NULL; + break; + + case 'Y': /* The year. */ + LEGAL_ALT(ALT_E); + i = TM_YEAR_BASE; + if (!(_NRT_convNum(&bp, &i, 0, 9999))) + return NULL; + tm->tm_year = i - TM_YEAR_BASE; + break; + + case 'y': /* The year within 100 years of the epoch. */ + LEGAL_ALT(ALT_E | ALT_O); + if (!(_NRT_convNum(&bp, &i, 0, 99))) + return NULL; + + if (split_year) + { + tm->tm_year = ((tm->tm_year / 100) * 100) + i; + break; + } + split_year = 1; + if (i <= 68) + tm->tm_year = i + 2000 - TM_YEAR_BASE; + else + tm->tm_year = i + 1900 - TM_YEAR_BASE; + break; + /* + * Miscellaneous conversions. + */ + case 'n': /* Any kind of white-space. */ + case 't': + LEGAL_ALT(0); + while (isspace(*bp)) + bp++; + break; + + default: /* Unknown/unsupported conversion. */ + return NULL; + } + + } + + /* LINTED functional specification */ + return ((char *) bp); +} + +static int _NRT_convNum(const char **buf, int *dest, int llim, int ulim) +{ + int result = 0; + + /* The limit also determines the number of valid digits. */ + int rulim = ulim; + + if (**buf < '0' || **buf > '9') + return 0; + + do + { + result *= 10; + result += *(*buf)++ - '0'; + rulim /= 10; + } + while ((result * 10 <= ulim) && rulim && **buf >= '0' && **buf <= '9'); + + if (result < llim || result > ulim) + return 0; + + *dest = result; + return 1; +} diff --git a/modules/c/nrt/source/Debug.c b/modules/c/nrt/source/Debug.c new file mode 100644 index 000000000..34ee73cf9 --- /dev/null +++ b/modules/c/nrt/source/Debug.c @@ -0,0 +1,121 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nrt/Debug.h" + +#ifdef NRT_DEBUG + +#ifndef WIN32 +# include +# include +#endif + +NRTPROT(void *) nrt_Debug_malloc(const char *file, int line, size_t sz) +{ + /* The pointer to allocate */ + void *p; + FILE *f; + char name[512]; + +#ifndef WIN32 + NRT_SNPRINTF(name, 512, "%s.%d", NRT_MEM_LOG, getpid()); +#else + /* This can easily be modified to use GetCurrentProcessId() */ + strcpy(name, NRT_MEM_LOG); +#endif + + f = fopen(name, "a"); + assert(f); + + fprintf(f, "REQUEST: malloc\t[%d]\n", sz); + + p = malloc(sz); + fprintf(f, "\tMALLOC\t%p\t%d\t%s\t%d\n", p, sz, file, line); + + fclose(f); + return p; +} + +NRTPROT(void *) nrt_Debug_realloc(const char *file, int line, void *ptr, + size_t sz) +{ + void *p; + char name[512]; + FILE *f; + +#ifndef WIN32 + NRT_SNPRINTF(name, 512, "%s.%d", NRT_MEM_LOG, getpid()); +#else + /* This can easily be modified to use GetCurrentProcessId() */ + strcpy(name, NRT_MEM_LOG); +#endif + + f = fopen(name, "a"); + assert(f); + + fprintf(f, "REQUEST: realloc\t[%p]\t[%d]\n", ptr, sz); + p = realloc(ptr, sz); + fprintf(f, "\tREALLOC\t%p\t%p\t%d\t%s\t%d\n", p, ptr, sz, file, line); + + fclose(f); + return p; +} + +NRTPROT(void) nrt_Debug_free(const char *file, int line, void *ptr) +{ + FILE *f; + char name[512]; + +#ifndef WIN32 + NRT_SNPRINTF(name, 512, "%s.%d", NRT_MEM_LOG, getpid()); +#else + /* This can easily be modified to use GetCurrentProcessId() */ + strcpy(name, NRT_MEM_LOG); +#endif + + f = fopen(name, "a"); + assert(f); + + fprintf(f, "REQUEST: free\t[%p]\n", ptr); + + free(ptr); + + fprintf(f, "\tFREE\t%s\t%d\n", file, line); + + fclose(f); + +} +#endif + +NRTPROT(void) nrt_Debug_flogf(FILE * file, const char *format, ...) +{ +#if defined(NRT_DEBUG) + va_list args; + va_start(args, format); + vfprintf(file, format, args); + va_end(args); +#else + /* Silence compiler warnings about unused variables */ + (void)file; + (void)format; +#endif +} diff --git a/modules/c/nrt/source/DirectoryUnix.c b/modules/c/nrt/source/DirectoryUnix.c new file mode 100644 index 000000000..3a2bb56bf --- /dev/null +++ b/modules/c/nrt/source/DirectoryUnix.c @@ -0,0 +1,89 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef WIN32 + +#include "nrt/Directory.h" + +typedef struct _DirectoryUnix +{ + DIR *handle; +} +DirectoryUnix; + +NRTAPI(nrt_Directory *) nrt_Directory_construct(nrt_Error * error) +{ + DirectoryUnix *dir = (DirectoryUnix *) NRT_MALLOC(sizeof(DirectoryUnix)); + + if (!dir) + { + nrt_Error_init(error, NRT_STRERROR(NRT_ERRNO), NRT_CTXT, + NRT_ERR_MEMORY); + return NULL; + } + dir->handle = NULL; + return dir; +} + +NRTAPI(const char *) nrt_Directory_findFirstFile(nrt_Directory * dir, + const char *path) +{ + DirectoryUnix *nDir = (DirectoryUnix *) dir; + nDir->handle = opendir(path); + if (nDir->handle == NULL) + return NULL; + return nrt_Directory_findNextFile(dir); +} + +NRTAPI(const char *) nrt_Directory_findNextFile(nrt_Directory * dir) +{ + DirectoryUnix *nDir = (DirectoryUnix *) dir; + struct dirent *entry = NULL; + entry = readdir(nDir->handle); + if (entry == NULL) + return NULL; + return entry->d_name; +} + +NRTAPI(void) nrt_Directory_destruct(nrt_Directory ** dir) +{ + if (*dir) + { + DirectoryUnix *nDir = (DirectoryUnix *) * dir; + if (nDir->handle != NULL) + { + assert(nDir->handle); + closedir(nDir->handle); + } + NRT_FREE(nDir); + *dir = NULL; + } +} + +NRTAPI(NRT_BOOL) nrt_Directory_exists(const char *path) +{ + struct stat info; + if (stat(path, &info) == -1) + return NRT_FAILURE; + return (S_ISDIR(info.st_mode)); +} +#endif diff --git a/modules/c/nrt/source/DirectoryWin32.c b/modules/c/nrt/source/DirectoryWin32.c new file mode 100644 index 000000000..96cb51c04 --- /dev/null +++ b/modules/c/nrt/source/DirectoryWin32.c @@ -0,0 +1,104 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nrt/Directory.h" + +#ifdef WIN32 + +NRT_CXX_GUARD typedef struct _DirectoryWin32 +{ + HANDLE handle; + WIN32_FIND_DATA fileData; +} +DirectoryWin32; + +/*! + * Create a directory object. Gives back a directory object + * \param error An error to populate on failure + * \return A directory object + */ +NRTAPI(nrt_Directory *) nrt_Directory_construct(nrt_Error * error) +{ + DirectoryWin32 *dir = (DirectoryWin32 *) NRT_MALLOC(sizeof(DirectoryWin32)); + if (!dir) + { + nrt_Error_init(error, NRT_STRERROR(NRT_ERRNO), NRT_CTXT, + NRT_ERR_MEMORY); + return NULL; + } + dir->handle = INVALID_HANDLE_VALUE; + + return (nrt_Directory *) dir; +} + +/*! + * Find the first file in a directory. + * + * + */ + +NRTAPI(const char *) nrt_Directory_findFirstFile(nrt_Directory * dir, + const char *path) +{ + DirectoryWin32 *nDir = (DirectoryWin32 *) dir; + char buffer[NRT_MAX_PATH] = ""; + NRT_SNPRINTF(buffer, NRT_MAX_PATH, "%s\\*", path); + nDir->handle = FindFirstFile(buffer, &(nDir->fileData)); + if (nDir->handle == INVALID_HANDLE_VALUE) + return NULL; + return nDir->fileData.cFileName; +} + +NRTAPI(const char *) nrt_Directory_findNextFile(nrt_Directory * dir) +{ + DirectoryWin32 *nDir = (DirectoryWin32 *) dir; + if (FindNextFile(nDir->handle, &(nDir->fileData)) == 0) + return NULL; + return nDir->fileData.cFileName; +} + +NRTAPI(void) nrt_Directory_destruct(nrt_Directory ** dir) +{ + if (*dir) + { + DirectoryWin32 *nDir = (DirectoryWin32 *) * dir; + FindClose(nDir->handle); + nDir->handle = INVALID_HANDLE_VALUE; + NRT_FREE(*dir); + *dir = NULL; + } +} + +NRTAPI(NRT_BOOL) nrt_Directory_exists(const char *dir) +{ + const DWORD what = GetFileAttributes(dir); + if (what == INVALID_FILE_ATTRIBUTES) + return NRT_FAILURE; + + if (what & FILE_ATTRIBUTE_DIRECTORY) + return NRT_SUCCESS; + return NRT_FAILURE; + +} + +NRT_CXX_ENDGUARD +#endif diff --git a/modules/c/nrt/source/Error.c b/modules/c/nrt/source/Error.c new file mode 100644 index 000000000..4adff5605 --- /dev/null +++ b/modules/c/nrt/source/Error.c @@ -0,0 +1,152 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nrt/Error.h" + +NRTPRIV(void) _NRT_Error_fillString(char *toFill, size_t maxLength, + const char *from) +{ + const size_t strlenFrom = strlen(from); + const size_t len = (strlenFrom < maxLength) ? strlenFrom : maxLength; + memset(toFill, 0, maxLength + 1); + memcpy(toFill, from, len); +} + +NRTPROT(void) nrt_Error_init(nrt_Error * error, const char *message, + const char *file, int line, const char *func, + int level) +{ + _NRT_Error_fillString(error->message, NRT_MAX_EMESSAGE, message); + _NRT_Error_fillString(error->file, NRT_MAX_PATH, file); + _NRT_Error_fillString(error->func, NRT_MAX_PATH, func); + + error->line = line; + error->level = level; +} + +NRTPRIV(const char *) _NRT_Error_urgency(int level) +{ + switch (level) + { + case NRT_ERR_MEMORY: + return "During memory allocation"; + + case NRT_ERR_OPENING_FILE: + return "While opening file"; + + case NRT_ERR_READING_FROM_FILE: + return "While reading from file"; + + case NRT_ERR_SEEKING_IN_FILE: + return "While seeking in file"; + + case NRT_ERR_WRITING_TO_FILE: + return "While writing to file"; + + case NRT_ERR_STAT_FILE: + return "While querying file info"; + + case NRT_ERR_LOADING_DLL: + return "While loading DLL"; + + case NRT_ERR_UNLOADING_DLL: + return "While unloading DLL"; + + case NRT_ERR_RETRIEVING_DLL_HOOK: + return "While retrieving DLL hook"; + + case NRT_ERR_UNINITIALIZED_DLL_READ: + return "Trying to read from uninitialized DLL"; + + case NRT_ERR_INVALID_PARAMETER: + return "Attempt to make use of invalid parameter"; + + case NRT_ERR_INVALID_OBJECT: + return "Trying to perform an operation on an invalid object"; + + case NRT_ERR_INVALID_FILE: + return "Invalid file"; + + case NRT_ERR_COMPRESSION: + return "Invalid compression type"; + + case NRT_ERR_DECOMPRESSION: + return "Invalid decompression"; + + } + return "UNK"; +} + +void nrt_Error_flogf(nrt_Error * error, FILE * file, int level, + const char *format, ...) +{ + va_list args; + if (error->level < level) + return; + va_start(args, format); + + fprintf(file, "Error [%s] (%s, %d, %s): '%s' : ", + _NRT_Error_urgency(error->level), error->file, error->line, + error->func, + (error->level == + NRT_ERR_UNK) ? ("Unknown Error") : (error->message)); + vfprintf(file, format, args); + va_end(args); +} + +void nrt_Error_fprintf(nrt_Error * error, FILE * file, const char *format, ...) +{ + va_list args; + va_start(args, format); + fprintf(file, "Error [%s] (%s, %d, %s): '%s' : ", + _NRT_Error_urgency(error->level), error->file, error->line, + error->func, + (error->level == + NRT_ERR_UNK) ? ("Unknown Error") : (error->message)); + vfprintf(file, format, args); + va_end(args); +} + +NRTAPI(void) nrt_Error_print(nrt_Error * error, FILE * file, + const char *userMessage) +{ + nrt_Error_fprintf(error, file, "%s\n", userMessage); +} + +NRTPROT(void) nrt_Error_initf(nrt_Error * error, const char *file, int line, + const char *func, int level, const char *format, + ...) +{ + va_list args; + va_start(args, format); + + NRT_VSNPRINTF(error->message, NRT_MAX_EMESSAGE + 1, format, args); + va_end(args); + + _NRT_Error_fillString(error->file, NRT_MAX_PATH, file); + _NRT_Error_fillString(error->func, NRT_MAX_PATH, func); + + error->line = line; + error->level = level; + + return; +} diff --git a/modules/c/nrt/source/HashTable.c b/modules/c/nrt/source/HashTable.c new file mode 100644 index 000000000..178da9182 --- /dev/null +++ b/modules/c/nrt/source/HashTable.c @@ -0,0 +1,495 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nrt/HashTable.h" + +NRTAPI(nrt_HashTable *) nrt_HashTable_construct(int nbuckets, nrt_Error * error) +{ + int i; + int hashSize; + + /* Create the hash table object itself */ + nrt_HashTable *ht = (nrt_HashTable *) NRT_MALLOC(sizeof(nrt_HashTable)); + if (!ht) + { + /* If we had problems, error population and return */ + nrt_Error_init(error, NRT_STRERROR(NRT_ERRNO), NRT_CTXT, + NRT_ERR_MEMORY); + return NULL; + } + + /* Adopt the data by default */ + ht->adopt = NRT_DATA_ADOPT; + + /* Size of all of our chains */ + hashSize = sizeof(nrt_List) * nbuckets; + + /* Dont forget to set nbuckets in the object */ + ht->nbuckets = nbuckets; + + /* Allocate the list of lists (still need to allocate each list */ + ht->buckets = (nrt_List **) NRT_MALLOC(hashSize); + if (!ht->buckets) + { + /* If we had problems, error population, and */ + /* free the object we have and return */ + nrt_Error_init(error, NRT_STRERROR(NRT_ERRNO), NRT_CTXT, + NRT_ERR_MEMORY); + /* Dont bother with the destructor */ + NRT_FREE(ht); + return NULL; + } + /* Make sure if we have to call the destructor we are good */ + memset(ht->buckets, 0, hashSize); + + /* Foreach list, construct */ + for (i = 0; i < nbuckets; i++) + { + + ht->buckets[i] = nrt_List_construct(error); + + /* Our destructor is smart enough to delete only non-NULL vals */ + /* Not only that the constructor populated our error already */ + if (!ht->buckets[i]) + { + nrt_HashTable_destruct(&ht); + return NULL; + } + } + + /* Set ourselves up with a default hash */ + /* We can always change it !! */ + nrt_HashTable_initDefaults(ht); + + /* We are good, so return */ + return ht; +} + +NRTAPI(void) nrt_HashTable_setPolicy(nrt_HashTable * ht, int policy) +{ + assert(ht); + ht->adopt = policy; +} + +NRTAPI(unsigned int) __NRT_HashTable_defaultHash(nrt_HashTable * ht, const char *key) +{ + const char *p = key; + const char *end = &key[strlen(key) - 1]; + char c; + int hash = 0; + + while (p < end) + { + c = *p++; + + if (c > 0140) + c -= 40; + hash = ((hash << 3) + (hash >> 28) + c); + } + return (unsigned) ((hash & 07777777777) % ht->nbuckets); +} + +NRTAPI(void) nrt_HashTable_initDefaults(nrt_HashTable * ht) +{ + /* Point our hash function at the default */ + ht->hash = &__NRT_HashTable_defaultHash; +} + +NRTAPI(void) nrt_HashTable_destruct(nrt_HashTable ** ht) +{ + /* If the hash table exists at all */ + if (*ht) + { + /* If the linked list of lists exists */ + if ((*ht)->buckets) + { + int i; + + /* This is tricky. Because we are allocating */ + /* the list first, we may have */ + for (i = 0; i < (*ht)->nbuckets; i++) + { + nrt_List *l = (*ht)->buckets[i]; + + /* If this list is alive, we need to get rid of */ + /* its keys and then delete it */ + if (l != NULL) + { + /* While we have elements */ + while (!nrt_List_isEmpty(l)) + { + /* Get the next element */ + nrt_Pair *pair = (nrt_Pair *) nrt_List_popFront(l); + + /* If there is a pair */ + if (pair) + { + /* Extract the key data, which we KNOW */ + /* That was dynamically allocated by us */ + char *key = pair->key; + + /* If its there */ + if (key) + { + /* Free and NULL it */ + NRT_FREE(key); + } + /* If the adoption policy is to adopt... */ + if ((*ht)->adopt) + { + /* Then we have to do deletion ourselves */ + NRT_DATA *data = pair->data; + /* If the data exists */ + if (data) + { + /* Free the data and NULL it */ + NRT_FREE(data); + } + } + /* Finally, we know that we allocated the */ + /* pair, so lets free it */ + NRT_FREE(pair); + } + } + /* Now the list is empty, let's destroy it */ + nrt_List_destruct(&((*ht)->buckets[i])); + } + /* Now go on to the next bucket */ + } + NRT_FREE((*ht)->buckets); + } + + NRT_FREE(*ht); + *ht = NULL; + } +} + +NRTAPI(NRT_BOOL) nrt_HashTable_exists(nrt_HashTable * ht, const char *key) +{ + /* This is a SERIOUS copout!!! */ + if (nrt_HashTable_find(ht, key) == NULL) + return NRT_FAILURE; + return NRT_SUCCESS; +} + +NRTAPI(NRT_DATA *) nrt_HashTable_remove(nrt_HashTable * ht, const char *key) +{ + /* Find out which list it would be in */ + int bucket = ht->hash(ht, key); + + /* Get the list at this bucket */ + nrt_List *l = ht->buckets[bucket]; + + /* Set our iterator to the beginning */ + nrt_ListIterator iter = nrt_List_begin(l); + + /* Set an iterator at the end */ + nrt_ListIterator end = nrt_List_end(l); + + /* While the list iterator hasnt reached the end */ + while (nrt_ListIterator_notEqualTo(&iter, &end)) + { + /* Get the pair at this node */ + nrt_Pair *pair = (nrt_Pair *) nrt_ListIterator_get(&iter); + + /* We'll see */ + assert(pair); + + /* We found a match, remove and go home */ + if (strcmp(pair->key, key) == 0) + { + NRT_DATA *data = pair->data; + + /* Remove at this point from l */ + nrt_List_remove(l, &iter); + + /* Delete the key -- that's ours */ + NRT_FREE(pair->key); + + /* Free the pair */ + NRT_FREE(pair); + + /* Return the value -- that's yours */ + return data; + } + /* We didn't get a match, so lets increment again */ + nrt_ListIterator_increment(&iter); + } + /* We slipped out of the while loop unsuccessfully */ + return NULL; +} + +NRTPRIV(int) printIt(nrt_HashTable * ht, nrt_Pair * pair, NRT_DATA * userData, + nrt_Error * error) +{ + /* Silence compiler warnings about unused variables */ + (void)ht; + (void)userData; + (void)error; + +#ifdef NRT_DEBUG + if (pair) + { + printf("{%p} [%s]: '%p'\n", pair, pair->key, pair->data); + } + else + { + printf("No pair defined at iter pos!\n"); + } +#else + (void)pair; +#endif + return 1; +} + +NRTAPI(void) nrt_HashTable_print(nrt_HashTable * ht) +{ + nrt_Error e; + NRT_HASH_FUNCTOR fn = printIt; + nrt_HashTable_foreach(ht, fn, NULL, &e); +} + +NRTAPI(NRT_BOOL) nrt_HashTable_foreach(nrt_HashTable * ht, NRT_HASH_FUNCTOR fn, + NRT_DATA * userData, nrt_Error * error) +{ + int i; + for (i = 0; i < ht->nbuckets; i++) + { + nrt_List *l = ht->buckets[i]; + nrt_ListIterator iter = nrt_List_begin(l); + nrt_ListIterator end = nrt_List_end(l); + while (nrt_ListIterator_notEqualTo(&iter, &end)) + { + nrt_Pair *pair = (nrt_Pair *) nrt_ListIterator_get(&iter); + if (!(*fn) (ht, pair, userData, error)) + return 0; + nrt_ListIterator_increment(&iter); + } + } + return 1; +} + +NRTAPI(nrt_HashTable *) nrt_HashTable_clone(nrt_HashTable * source, + NRT_DATA_ITEM_CLONE cloner, + nrt_Error * error) +{ + int i; + /* This is the simplest way of setting up the hash */ + nrt_HashTable *ht = NULL; + + if (source) + { + ht = nrt_HashTable_construct(source->nbuckets, error); + if (!ht) + return NULL; + + /* Make sure the policy is the same! */ + ht->adopt = source->adopt; + + /* Now we want to walk the list and insert items into the hash */ + for (i = 0; i < source->nbuckets; i++) + { + nrt_List *l = source->buckets[i]; + nrt_ListIterator iter = nrt_List_begin(l); + nrt_ListIterator end = nrt_List_end(l); + while (nrt_ListIterator_notEqualTo(&iter, &end)) + { + /* Foreach item in each list... */ + nrt_Pair *pair = (nrt_Pair *) nrt_ListIterator_get(&iter); + + /* Use the function pointer to clone the object... */ + NRT_DATA *newData = (NRT_DATA *) cloner(pair->data, error); + if (!newData) + { + nrt_HashTable_destruct(&ht); + return NULL; + } + + /* ... and then insert it with the key into the new table */ + if (!nrt_HashTable_insert(ht, pair->key, newData, error)) + { + nrt_HashTable_destruct(&ht); + return NULL; + } + + nrt_ListIterator_increment(&iter); + } + } + } + else + { + nrt_Error_initf(error, NRT_CTXT, NRT_ERR_INVALID_OBJECT, + "Trying to clone NULL pointer"); + } + return ht; +} + +NRTAPI(NRT_BOOL) nrt_HashTable_insert(nrt_HashTable * ht, const char *key, + NRT_DATA * data, nrt_Error * error) +{ + /* Find the bucket */ + int bucket = ht->hash(ht, key); + + /* Malloc the pair -- that's our container item */ + nrt_Pair *p = (nrt_Pair *) NRT_MALLOC(sizeof(nrt_Pair)); + if (!p) + { + /* There was a memory allocation error */ + nrt_Error_init(error, NRT_STRERROR(NRT_ERRNO), NRT_CTXT, + NRT_ERR_MEMORY); + /* Retreat! */ + return 0; + } + + /* Initialize the new pair */ + /* This makes a copy of the key, but uses the data directly */ + nrt_Pair_init(p, key, data); + + /* Push the pair back into the list */ + return nrt_List_pushBack(ht->buckets[bucket], p, error); +} + +NRTAPI(nrt_Pair *) nrt_HashTable_find(nrt_HashTable * ht, const char *key) +{ + /* Retrieve the pocket */ + int bucket = ht->hash(ht, key); + + /* Get the list for it */ + nrt_List *l = ht->buckets[bucket]; + + /* Get an iterator to the front */ + nrt_ListIterator iter = nrt_List_begin(l); + + /* Point one at the back */ + nrt_ListIterator end = nrt_List_end(l); + + /* While we are retrieving... */ + while (nrt_ListIterator_notEqualTo(&iter, &end)) + { + + nrt_Pair *pair = (nrt_Pair *) nrt_ListIterator_get(&iter); + + /* Should NOT get a null pair */ + assert(pair); + + /* We have a match!!! */ + if (strcmp(pair->key, key) == 0) + { + return pair; + } + /* Otherwise, increment */ + nrt_ListIterator_increment(&iter); + } + return NULL; +} + +NRTAPI(nrt_HashTableIterator) nrt_HashTable_begin(nrt_HashTable * ht) +{ + nrt_HashTableIterator hash_iterator; + /* Be ruthless with our assertions */ + assert(ht); + + hash_iterator.curBucket = -1; /* default to the 'end' */ + hash_iterator.listIter.current = NULL; + hash_iterator.hash = ht; + + if (ht->buckets) + { + int i; + for (i = 0; i < ht->nbuckets && hash_iterator.curBucket < 0; i++) + { + nrt_List *l = ht->buckets[i]; + if (l != NULL && nrt_List_size(l) > 0) + { + hash_iterator.curBucket = i; + hash_iterator.listIter = nrt_List_begin(l); + } + } + } + return hash_iterator; +} + +NRTAPI(nrt_HashTableIterator) nrt_HashTable_end(nrt_HashTable * ht) +{ + nrt_HashTableIterator hash_iterator; + hash_iterator.curBucket = -1; + hash_iterator.listIter.current = NULL; + hash_iterator.hash = ht; + return hash_iterator; +} + +NRTAPI(NRT_BOOL) nrt_HashTableIterator_equals(nrt_HashTableIterator * it1, + nrt_HashTableIterator * it2) +{ + return it1->curBucket == it2->curBucket + && nrt_ListIterator_equals(&it1->listIter, &it2->listIter) + && it1->hash == it2->hash; +} + +NRTAPI(NRT_BOOL) nrt_HashTableIterator_notEqualTo(nrt_HashTableIterator * it1, + nrt_HashTableIterator * it2) +{ + return !nrt_HashTableIterator_equals(it1, it2); +} + +NRTAPI(void) nrt_HashTableIterator_increment(nrt_HashTableIterator * iter) +{ + NRT_BOOL found = 0; + if (iter->hash->buckets && iter->curBucket >= 0 + && iter->curBucket < iter->hash->nbuckets) + { + nrt_List *l = iter->hash->buckets[iter->curBucket]; + nrt_ListIterator end = nrt_List_end(l); + nrt_ListIterator_increment(&iter->listIter); + if (nrt_ListIterator_notEqualTo(&iter->listIter, &end)) + found = 1; + else + { + int i; + for (i = iter->curBucket + 1; i < iter->hash->nbuckets && !found; + i++) + { + nrt_List *l = iter->hash->buckets[i]; + if (l != NULL && nrt_List_size(l) > 0) + { + iter->curBucket = i; + iter->listIter = nrt_List_begin(l); + found = 1; + } + } + } + } + + if (!found) + { + /* set to "end" */ + iter->curBucket = -1; + iter->listIter.current = NULL; + } +} + +NRTAPI(nrt_Pair *) nrt_HashTableIterator_get(nrt_HashTableIterator * iter) +{ + if (iter->curBucket >= 0 && iter->listIter.current) + return (nrt_Pair *) nrt_ListIterator_get(&iter->listIter); + return NULL; +} diff --git a/modules/c/nrt/source/IOHandleUnix.c b/modules/c/nrt/source/IOHandleUnix.c new file mode 100644 index 000000000..90655e953 --- /dev/null +++ b/modules/c/nrt/source/IOHandleUnix.c @@ -0,0 +1,160 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef WIN32 + +#include "nrt/IOHandle.h" + +NRTAPI(nrt_IOHandle) nrt_IOHandle_create(const char *fname, + nrt_AccessFlags access, + nrt_CreationFlags creation, + nrt_Error * error) +{ + int fd; + if (access & NRT_ACCESS_WRITEONLY) + creation |= NRT_TRUNCATE; + fd = open(fname, access | creation, NRT_DEFAULT_PERM); + + if (fd == -1) + { + nrt_Error_init(error, strerror(errno), NRT_CTXT, NRT_ERR_OPENING_FILE); + } + + return fd; +} + +NRTAPI(NRT_BOOL) nrt_IOHandle_read(nrt_IOHandle handle, char *buf, size_t size, + nrt_Error * error) +{ + ssize_t bytesRead = 0; /* Number of bytes read during last read + * operation */ + size_t totalBytesRead = 0; /* Total bytes read thus far */ + int i; /* iterator */ + + /* make sure the user actually wants data */ + if (size <= 0) + return NRT_SUCCESS; + + /* Interrogate the IO handle */ + for (i = 1; i <= NRT_MAX_READ_ATTEMPTS; i++) + { + /* Make the next read */ + bytesRead = read(handle, buf + totalBytesRead, size - totalBytesRead); + + switch (bytesRead) + { + case -1: /* Some type of error occured */ + switch (errno) + { + case EINTR: + case EAGAIN: /* A non-fatal error occured, keep trying */ + break; + + default: /* We failed */ + goto CATCH_ERROR; + } + break; + + case 0: /* EOF (unexpected) */ + nrt_Error_init(error, "Unexpected end of file", NRT_CTXT, + NRT_ERR_READING_FROM_FILE); + return NRT_FAILURE; + + default: /* We made progress */ + totalBytesRead += (size_t) bytesRead; + + } /* End of switch */ + + /* Check for success */ + if (totalBytesRead == size) + { + return NRT_SUCCESS; + } + + } /* End of for */ + + /* We fell out of the for loop (not good) */ + /* goto CATCH_ERROR; */ + + /* An error occured */ + CATCH_ERROR: + + nrt_Error_init(error, strerror(errno), NRT_CTXT, NRT_ERR_READING_FROM_FILE); + return NRT_FAILURE; +} + +NRTAPI(NRT_BOOL) nrt_IOHandle_write(nrt_IOHandle handle, const char *buf, + size_t size, nrt_Error * error) +{ + size_t bytesActuallyWritten = 0; + + do + { + const ssize_t bytesThisWrite = + write(handle, buf + bytesActuallyWritten, size); + if (bytesThisWrite == -1) + { + nrt_Error_init(error, strerror(errno), NRT_CTXT, + NRT_ERR_WRITING_TO_FILE); + return NRT_FAILURE; + } + bytesActuallyWritten += bytesThisWrite; + } + while (bytesActuallyWritten < size); + + return NRT_SUCCESS; +} + +NRTAPI(nrt_Off) nrt_IOHandle_seek(nrt_IOHandle handle, nrt_Off offset, + int whence, nrt_Error * error) +{ + nrt_Off off = lseek(handle, offset, whence); + if (off == (nrt_Off) - 1) + { + nrt_Error_init(error, strerror(errno), NRT_CTXT, + NRT_ERR_SEEKING_IN_FILE); + } + return off; +} + +NRTAPI(nrt_Off) nrt_IOHandle_tell(nrt_IOHandle handle, nrt_Error * error) +{ + return nrt_IOHandle_seek(handle, 0, SEEK_CUR, error); +} + +NRTAPI(nrt_Off) nrt_IOHandle_getSize(nrt_IOHandle handle, nrt_Error * error) +{ + struct stat buf; + int rval = fstat(handle, &buf); + if (rval == -1) + { + nrt_Error_init(error, strerror(errno), NRT_CTXT, NRT_ERR_STAT_FILE); + return rval; + } + return buf.st_size; +} + +NRTAPI(void) nrt_IOHandle_close(nrt_IOHandle handle) +{ + close(handle); +} +#endif diff --git a/modules/c/nrt/source/IOHandleWin32.c b/modules/c/nrt/source/IOHandleWin32.c new file mode 100644 index 000000000..5c726ae66 --- /dev/null +++ b/modules/c/nrt/source/IOHandleWin32.c @@ -0,0 +1,182 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nrt/IOHandle.h" + +#ifdef WIN32 + +NRTAPI(nrt_IOHandle) nrt_IOHandle_create(const char *fname, + nrt_AccessFlags access, + nrt_CreationFlags creation, + nrt_Error * error) +{ + HANDLE handle; + + if (access & NRT_ACCESS_WRITEONLY) + { + WIN32_FIND_DATA findData; + handle = FindFirstFile(fname, &findData); + if (handle != INVALID_HANDLE_VALUE) + { + creation |= TRUNCATE_EXISTING; + FindClose(handle); + } + } + + handle = + CreateFile(fname, access, FILE_SHARE_READ, NULL, creation, + FILE_ATTRIBUTE_NORMAL, NULL); + + if (handle == INVALID_HANDLE_VALUE) + { + nrt_Error_init(error, NRT_STRERROR(NRT_ERRNO), NRT_CTXT, + NRT_ERR_OPENING_FILE); + } + return handle; +} + +NRTAPI(NRT_BOOL) nrt_IOHandle_read(nrt_IOHandle handle, char *buf, size_t size, + nrt_Error * error) +{ + static const DWORD MAX_READ_SIZE = (DWORD)-1; + size_t bytesRead = 0; + size_t bytesRemaining = size; + + while (bytesRead < size) + { + /* Determine how many bytes to read */ + const DWORD bytesToRead = (bytesRemaining > MAX_READ_SIZE) ? + MAX_READ_SIZE : (DWORD)bytesRemaining; + + /* Read from file */ + DWORD bytesThisRead = 0; + if (!ReadFile(handle, + buf + bytesRead, + bytesToRead, + &bytesThisRead, + NULL)) + { + nrt_Error_init(error, NRT_STRERROR(NRT_ERRNO), NRT_CTXT, + NRT_ERR_READING_FROM_FILE); + return NRT_FAILURE; + } + else if (bytesThisRead == 0) + { + // ReadFile does not fail when finding the EOF -- + // instead it reports 0 bytes read, so this stops an infinite loop + // from Unexpected EOF + nrt_Error_init(error, "Unexpected end of file", NRT_CTXT, + NRT_ERR_READING_FROM_FILE); + return NRT_FAILURE; + } + + bytesRead += bytesThisRead; + bytesRemaining -= bytesThisRead; + } + + return NRT_SUCCESS; +} + +NRTAPI(NRT_BOOL) nrt_IOHandle_write(nrt_IOHandle handle, const char *buf, + size_t size, nrt_Error * error) +{ + static const DWORD MAX_WRITE_SIZE = (DWORD)-1; + size_t bytesRemaining = size; + size_t bytesWritten = 0; + + while (bytesWritten < size) + { + /* Determine how many bytes to write */ + const DWORD bytesToWrite = (bytesRemaining > MAX_WRITE_SIZE) ? + MAX_WRITE_SIZE : (DWORD)bytesRemaining; + + /* Write the data */ + DWORD bytesThisWrite = 0; + + if (!WriteFile(handle, + buf + bytesWritten, + bytesToWrite, + &bytesThisWrite, + NULL)) + { + /* If the function failed, we want to get the last error */ + nrt_Error_init(error, NRT_STRERROR(NRT_ERRNO), NRT_CTXT, + NRT_ERR_WRITING_TO_FILE); + /* And fail */ + return NRT_FAILURE; + } + + /* Otherwise, we want to accumulate this write until we are done */ + bytesRemaining -= bytesThisWrite; + bytesWritten += bytesThisWrite; + } + + return NRT_SUCCESS; +} + +NRTAPI(nrt_Off) nrt_IOHandle_seek(nrt_IOHandle handle, nrt_Off offset, + int whence, nrt_Error * error) +{ + LARGE_INTEGER largeInt; + int lastError; + largeInt.QuadPart = offset; + largeInt.LowPart = + SetFilePointer(handle, largeInt.LowPart, &largeInt.HighPart, whence); + + lastError = GetLastError(); + if ((largeInt.LowPart == INVALID_SET_FILE_POINTER) + && (lastError != NO_ERROR)) + { + nrt_Error_initf(error, NRT_CTXT, NRT_ERR_SEEKING_IN_FILE, + "SetFilePointer failed with error [%d]", lastError); + return (nrt_Off) - 1; + } + return (nrt_Off) largeInt.QuadPart; +} + +NRTAPI(nrt_Off) nrt_IOHandle_tell(nrt_IOHandle handle, nrt_Error * error) +{ + return nrt_IOHandle_seek(handle, 0, FILE_CURRENT, error); +} + +NRTAPI(nrt_Off) nrt_IOHandle_getSize(nrt_IOHandle handle, nrt_Error * error) +{ + DWORD ret; + DWORD highOff; + nrt_Uint64 off; + ret = GetFileSize(handle, &highOff); + if ((ret == -1)) + { + nrt_Error_initf(error, NRT_CTXT, NRT_ERR_STAT_FILE, + "GetFileSize failed with error [%d]", GetLastError()); + return (nrt_Off) - 1; + } + + off = (nrt_Uint64)highOff; + return (nrt_Off)((off << 32) + ret); +} + +NRTAPI(void) nrt_IOHandle_close(nrt_IOHandle handle) +{ + CloseHandle(handle); +} +#endif diff --git a/modules/c/nrt/source/IOInterface.c b/modules/c/nrt/source/IOInterface.c new file mode 100644 index 000000000..48e1e007f --- /dev/null +++ b/modules/c/nrt/source/IOInterface.c @@ -0,0 +1,427 @@ +#include "nrt/IOInterface.h" + +NRT_CXX_GUARD typedef struct _IOHandleControl +{ + nrt_IOHandle handle; + int mode; +} IOHandleControl; + +typedef struct _BufferIOControl +{ + char *buf; + size_t size; + size_t mark; + size_t bytesWritten; + NRT_BOOL ownBuf; +} BufferIOControl; + +NRTAPI(NRT_BOOL) nrt_IOInterface_read(nrt_IOInterface * io, char *buf, + size_t size, nrt_Error * error) +{ + return io->iface->read(io->data, buf, size, error); +} + +NRTAPI(NRT_BOOL) nrt_IOInterface_write(nrt_IOInterface * io, const char *buf, + size_t size, nrt_Error * error) +{ + return io->iface->write(io->data, buf, size, error); +} + +NRTAPI(NRT_BOOL) nrt_IOInterface_canSeek(nrt_IOInterface * io, + nrt_Error * error) +{ + return io->iface->canSeek(io->data, error); +} + +NRTAPI(nrt_Off) nrt_IOInterface_seek(nrt_IOInterface * io, nrt_Off offset, + int whence, nrt_Error * error) +{ + if (!nrt_IOInterface_canSeek(io, error) && offset != 0) + { + nrt_Error_init(error, "IO Interface does not support seeking", NRT_CTXT, + NRT_ERR_INVALID_OBJECT); + return (nrt_Off) - 1; + } + return io->iface->seek(io->data, offset, whence, error); +} + +NRTAPI(nrt_Off) nrt_IOInterface_tell(nrt_IOInterface * io, nrt_Error * error) +{ + return io->iface->tell(io->data, error); +} + +NRTAPI(nrt_Off) nrt_IOInterface_getSize(nrt_IOInterface * io, nrt_Error * error) +{ + return io->iface->getSize(io->data, error); +} + +NRTAPI(int) nrt_IOInterface_getMode(nrt_IOInterface * io, nrt_Error * error) +{ + return io->iface->getMode(io->data, error); +} + +NRTAPI(NRT_BOOL) nrt_IOInterface_close(nrt_IOInterface * io, nrt_Error * error) +{ + return io->iface->close(io->data, error); + +} + +NRTAPI(void) nrt_IOInterface_destruct(nrt_IOInterface ** io) +{ + if (*io) + { + if ((*io)->iface) + { + if ((*io)->data) + { + (*io)->iface->destruct((*io)->data); + free((*io)->data); + (*io)->data = NULL; + } + (*io)->iface = NULL; + } + NRT_FREE(*io); + *io = NULL; + } +} + +NRTPRIV(NRT_BOOL) IOHandleAdapter_read(NRT_DATA * data, char *buf, size_t size, + nrt_Error * error) +{ + IOHandleControl *control = (IOHandleControl *) data; + return nrt_IOHandle_read(control->handle, buf, size, error); +} + +NRTPRIV(NRT_BOOL) IOHandleAdapter_write(NRT_DATA * data, const char *buf, + size_t size, nrt_Error * error) +{ + IOHandleControl *control = (IOHandleControl *) data; + return nrt_IOHandle_write(control->handle, buf, size, error); +} + +NRTPRIV(NRT_BOOL) IOHandleAdapter_canSeek(NRT_DATA * data, nrt_Error * error) +{ + /* Silence compiler warnings about unused variables */ + (void)data; + (void)error; + return NRT_SUCCESS; +} + +NRTPRIV(nrt_Off) IOHandleAdapter_seek(NRT_DATA * data, nrt_Off offset, + int whence, nrt_Error * error) +{ + IOHandleControl *control = (IOHandleControl *) data; + return nrt_IOHandle_seek(control->handle, offset, whence, error); +} + +NRTPRIV(nrt_Off) IOHandleAdapter_tell(NRT_DATA * data, nrt_Error * error) +{ + IOHandleControl *control = (IOHandleControl *) data; + return nrt_IOHandle_tell(control->handle, error); +} + +NRTPRIV(nrt_Off) IOHandleAdapter_getSize(NRT_DATA * data, nrt_Error * error) +{ + IOHandleControl *control = (IOHandleControl *) data; + return nrt_IOHandle_getSize(control->handle, error); +} + +NRTPRIV(int) IOHandleAdapter_getMode(NRT_DATA * data, nrt_Error * error) +{ + IOHandleControl *control = (IOHandleControl *) data; + + /* Silence compiler warnings about unused variables */ + (void)error; + + return control->mode; +} + +NRTPRIV(NRT_BOOL) IOHandleAdapter_close(NRT_DATA * data, nrt_Error * error) +{ + IOHandleControl *control = (IOHandleControl *) data; + + /* Silence compiler warnings about unused variables */ + (void)error; + + if (control && control->handle && !NRT_INVALID_HANDLE(control->handle)) + { + nrt_IOHandle_close(control->handle); + + /* Invalidate the handle. Otherwise, if a caller closes this once, + * then opens another IOHandle that the OS happens to give the same + * underlying handle value to, then the caller closes this again, + * they will actually close the second IOHandle. + */ + control->handle = NRT_INVALID_HANDLE_VALUE; + } + return NRT_SUCCESS; +} + +NRTPRIV(void) IOHandleAdapter_destruct(NRT_DATA * data) +{ + /* Silence compiler warnings about unused variables */ + (void)data; +} + +NRTPRIV(NRT_BOOL) BufferAdapter_read(NRT_DATA * data, char *buf, size_t size, + nrt_Error * error) +{ + BufferIOControl *control = (BufferIOControl *) data; + + if (size > control->size - control->mark) + { + nrt_Error_init(error, "Invalid size requested - EOF", NRT_CTXT, + NRT_ERR_MEMORY); + return NRT_FAILURE; + } + + if (size > 0) + { + memcpy(buf, (char *) (control->buf + control->mark), size); + control->mark += size; + } + return NRT_SUCCESS; +} + +NRTPRIV(NRT_BOOL) BufferAdapter_write(NRT_DATA * data, const char *buf, + size_t size, nrt_Error * error) +{ + BufferIOControl *control = (BufferIOControl *) data; + + if (size > control->size - control->mark) + { + nrt_Error_init(error, "Invalid size requested - EOF", NRT_CTXT, + NRT_ERR_MEMORY); + return NRT_FAILURE; + } + + if (size > 0) + { + memcpy((char *) (control->buf + control->mark), buf, size); + control->mark += size; + if (control->mark > control->bytesWritten) + { + control->bytesWritten = control->mark; + } + } + return NRT_SUCCESS; +} + +NRTPRIV(NRT_BOOL) BufferAdapter_canSeek(NRT_DATA * data, nrt_Error * error) +{ + /* Silence compiler warnings about unused variables */ + (void)data; + (void)error; + + return NRT_SUCCESS; +} + +NRTPRIV(nrt_Off) BufferAdapter_seek(NRT_DATA * data, nrt_Off offset, int whence, + nrt_Error * error) +{ + BufferIOControl *control = (BufferIOControl *) data; + + if (whence == NRT_SEEK_SET) + { + if (offset >= (nrt_Off) control->size) + { + nrt_Error_init(error, "Invalid offset requested - EOF", NRT_CTXT, + NRT_ERR_MEMORY); + return -1; + } + control->mark = (size_t) offset; + } + else if (whence == NRT_SEEK_CUR) + { + if (offset >= (nrt_Off)control->size - (nrt_Off)control->mark) + { + nrt_Error_init(error, "Invalid offset requested - EOF", NRT_CTXT, + NRT_ERR_MEMORY); + return -1; + } + control->mark += (size_t) offset; + } + else + { + nrt_Error_init(error, "Invalid/unsupported seek directive", NRT_CTXT, + NRT_ERR_MEMORY); + return -1; + } + return control->mark; +} + +NRTPRIV(nrt_Off) BufferAdapter_tell(NRT_DATA * data, nrt_Error * error) +{ + BufferIOControl *control = (BufferIOControl *) data; + + /* Silence compiler warnings about unused variables */ + (void)error; + + return (nrt_Off) control->mark; +} + +NRTPRIV(nrt_Off) BufferAdapter_getSize(NRT_DATA * data, nrt_Error * error) +{ + BufferIOControl *control = (BufferIOControl *) data; + + /* Silence compiler warnings about unused variables */ + (void)error; + + return (nrt_Off) control->bytesWritten; +} + +NRTPRIV(int) BufferAdapter_getMode(NRT_DATA * data, nrt_Error * error) +{ + /* Silence compiler warnings about unused variables */ + (void)data; + (void)error; + + return NRT_ACCESS_READWRITE; +} + +NRTPRIV(NRT_BOOL) BufferAdapter_close(NRT_DATA * data, nrt_Error * error) +{ + /* Silence compiler warnings about unused variables */ + (void)data; + (void)error; + + /* nothing */ + return NRT_SUCCESS; +} + +NRTPRIV(void) BufferAdapter_destruct(NRT_DATA * data) +{ + BufferIOControl *control = (BufferIOControl *) data; + if (control && control->buf && control->ownBuf) + { + NRT_FREE(control->buf); + control->buf = NULL; + } +} + +NRTAPI(nrt_IOInterface *) nrt_IOHandleAdapter_construct(nrt_IOHandle handle, + int accessMode, + nrt_Error * error) +{ + static nrt_IIOInterface iIOHandle = { + &IOHandleAdapter_read, + &IOHandleAdapter_write, + &IOHandleAdapter_canSeek, + &IOHandleAdapter_seek, + &IOHandleAdapter_tell, + &IOHandleAdapter_getSize, + &IOHandleAdapter_getMode, + &IOHandleAdapter_close, + &IOHandleAdapter_destruct + }; + nrt_IOInterface *impl = NULL; + IOHandleControl *control = NULL; + + impl = (nrt_IOInterface *) NRT_MALLOC(sizeof(nrt_IOInterface)); + if (!impl) + { + nrt_Error_init(error, NRT_STRERROR(NRT_ERRNO), NRT_CTXT, + NRT_ERR_MEMORY); + goto CATCH_ERROR; + } + memset(impl, 0, sizeof(nrt_IOInterface)); + + control = (IOHandleControl *) NRT_MALLOC(sizeof(IOHandleControl)); + if (!control) + { + nrt_Error_init(error, NRT_STRERROR(NRT_ERRNO), NRT_CTXT, + NRT_ERR_MEMORY); + goto CATCH_ERROR; + } + memset(control, 0, sizeof(IOHandleControl)); + control->handle = handle; + control->mode = accessMode; + + impl->data = (NRT_DATA *) control; + impl->iface = &iIOHandle; + return impl; + + CATCH_ERROR: + { + if (impl) + nrt_IOInterface_destruct(&impl); + return NULL; + } +} + +NRTAPI(nrt_IOInterface *) nrt_IOHandleAdapter_open(const char *fname, + int accessFlags, + int creationFlags, + nrt_Error * error) +{ + nrt_IOHandle handle = nrt_IOHandle_create(fname, accessFlags, creationFlags, + error); + if (NRT_INVALID_HANDLE(handle)) + { + /* Save off the original error message (i.e. that the file doesn't + * exist or has invalid permissions) + * TODO: Would really like to use one of the nrt_Error print functions + */ + char origMessage[NRT_MAX_EMESSAGE + 1]; + strcpy(origMessage, error->message); + + nrt_Error_initf(error, NRT_CTXT, NRT_ERR_INVALID_OBJECT, + "Invalid IO handle (%s)", origMessage); + return NULL; + } + + return nrt_IOHandleAdapter_construct(handle, accessFlags, error); +} + +NRTAPI(nrt_IOInterface *) nrt_BufferAdapter_construct(char *buf, size_t size, + NRT_BOOL ownBuf, + nrt_Error * error) +{ + static nrt_IIOInterface bufferInterface = { + &BufferAdapter_read, + &BufferAdapter_write, + &BufferAdapter_canSeek, + &BufferAdapter_seek, + &BufferAdapter_tell, + &BufferAdapter_getSize, + &BufferAdapter_getMode, + &BufferAdapter_close, + &BufferAdapter_destruct + }; + nrt_IOInterface *impl = NULL; + BufferIOControl *control = NULL; + + impl = (nrt_IOInterface *) NRT_MALLOC(sizeof(nrt_IOInterface)); + if (!impl) + { + nrt_Error_init(error, NRT_STRERROR(NRT_ERRNO), NRT_CTXT, + NRT_ERR_MEMORY); + goto CATCH_ERROR; + } + memset(impl, 0, sizeof(nrt_IOInterface)); + + control = (BufferIOControl *) NRT_MALLOC(sizeof(BufferIOControl)); + if (!control) + { + nrt_Error_init(error, NRT_STRERROR(NRT_ERRNO), NRT_CTXT, + NRT_ERR_MEMORY); + goto CATCH_ERROR; + } + memset(control, 0, sizeof(BufferIOControl)); + control->buf = buf; + control->size = size; + control->ownBuf = ownBuf; + + impl->data = (NRT_DATA *) control; + impl->iface = &bufferInterface; + return impl; + + CATCH_ERROR: + { + if (impl) + nrt_IOInterface_destruct(&impl); + return NULL; + } +} + +NRT_CXX_ENDGUARD diff --git a/modules/c/nrt/source/IntStack.c b/modules/c/nrt/source/IntStack.c new file mode 100644 index 000000000..5ef32a389 --- /dev/null +++ b/modules/c/nrt/source/IntStack.c @@ -0,0 +1,111 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nrt/IntStack.h" + +NRTPROT(nrt_IntStack *) nrt_IntStack_construct(nrt_Error * error) +{ + nrt_IntStack *stk = (nrt_IntStack *) NRT_MALLOC(sizeof(nrt_IntStack)); + if (!stk) + { + nrt_Error_init(error, NRT_STRERROR(NRT_ERRNO), NRT_CTXT, + NRT_ERR_MEMORY); + return NULL; + } + + stk->sp = -1; + return stk; +} + +NRTPROT(nrt_IntStack *) nrt_IntStack_clone(nrt_IntStack * stack, + nrt_Error * error) +{ + int i; + nrt_IntStack *copy = nrt_IntStack_construct(error); + if (!copy) + return NULL; + + copy->sp = stack->sp; + + for (i = 0; i < NRT_INT_STACK_DEPTH; i++) + { + copy->st[i] = stack->st[i]; + } + return copy; + +} + +NRTPROT(void) nrt_IntStack_destruct(nrt_IntStack ** stk) +{ + if (*stk) + { + NRT_FREE(*stk); + *stk = NULL; + } +} + +NRTPROT(int) nrt_IntStack_top(nrt_IntStack * stack, nrt_Error * error) +{ + /* TODO: Someone should rewrite this class to not be so quirky */ + /* It is inconsistent with the rest of the library */ + if ((stack->sp >= 0) && (stack->sp < NRT_INT_STACK_DEPTH)) + { + return stack->st[stack->sp]; + } + + nrt_Error_initf(error, NRT_CTXT, NRT_ERR_INT_STACK_OVERFLOW, + "Stack pointing at depth: %d", stack->sp); + return 0; +} + +NRTPROT(int) nrt_IntStack_push(nrt_IntStack * stack, int n, nrt_Error * error) +{ + /* TODO: See above */ + if ((stack->sp >= -1) && (stack->sp < NRT_INT_STACK_DEPTH - 1)) + { + stack->st[++(stack->sp)] = n; + return 1; + } + + nrt_Error_initf(error, NRT_CTXT, NRT_ERR_INT_STACK_OVERFLOW, + "Stack pointing at depth: %d", stack->sp); + return 0; +} + +NRTPROT(int) nrt_IntStack_pop(nrt_IntStack * stack, nrt_Error * error) +{ + if ((stack->sp >= 0) && (stack->sp < NRT_INT_STACK_DEPTH)) + { + return stack->st[(stack->sp)--]; + } + /* This return value is nonsense. We need to */ + nrt_Error_initf(error, NRT_CTXT, NRT_ERR_INT_STACK_OVERFLOW, + "Stack pointing at depth: %d", stack->sp); + return 2147483647; +} + +NRTPROT(int) nrt_IntStack_depth(nrt_IntStack * stack, nrt_Error * error) +{ + /* Silence compiler warnings about unused variables */ + (void)error; + return stack->sp; +} diff --git a/modules/c/nrt/source/List.c b/modules/c/nrt/source/List.c new file mode 100644 index 000000000..dd305f310 --- /dev/null +++ b/modules/c/nrt/source/List.c @@ -0,0 +1,494 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; + * If not, see . + * + */ + +#include "nrt/List.h" + +NRTAPI(nrt_ListNode *) nrt_ListNode_construct(nrt_ListNode * prev, + nrt_ListNode * next, + NRT_DATA * data, + nrt_Error * error) +{ + nrt_ListNode *node = (nrt_ListNode *) NRT_MALLOC(sizeof(nrt_ListNode)); + if (node == NULL) + { + /* Init the error with the string value of errno */ + nrt_Error_init(error, NRT_STRERROR(NRT_ERRNO), NRT_CTXT, + NRT_ERR_MEMORY); + /* Return if we have a problem */ + return NULL; + } + + /* Attention!! Achtung!! This is a data pointer copy, */ + /* not copying an object. That means that YOU the user */ + /* of this API MUST allocate it yourself */ + /* And, of course, YOU must delete it as well!! */ + node->data = data; + + /* Attach up our nodes */ + node->next = next; + node->prev = prev; + + /* Return the new node */ + return node; +} + +NRTAPI(void) nrt_ListNode_destruct(nrt_ListNode ** this_node) +{ + if (*this_node) + { + NRT_FREE(*this_node); + *this_node = NULL; + } +} + +NRTAPI(NRT_BOOL) nrt_List_isEmpty(nrt_List * this_list) +{ + return !this_list || !this_list->first; +} + +NRTAPI(NRT_BOOL) nrt_List_pushFront(nrt_List * this_list, NRT_DATA * data, + nrt_Error * error) +{ + /* Construct a new node, with no surrounding context */ + nrt_ListNode *node = nrt_ListNode_construct(NULL, NULL, data, error); + if (!node) + { + /* The node constructor inited the error, so let's go home */ + return 0; + } + + /* Hook the links up manually */ + if (this_list->first) + { + /* Red wire to the green wire... */ + + /* Give the first link a previous (the new one) */ + this_list->first->prev = node; + + /* Point this one's next at the old first */ + node->next = this_list->first; + + /* So now, reassign the meaning of first to our new one */ + this_list->first = node; + } + /* Otherwise, we are the first and the last */ + /* (It was empty before) */ + else + this_list->first = this_list->last = node; + return 1; +} + +NRTAPI(NRT_BOOL) nrt_List_pushBack(nrt_List * this_list, NRT_DATA * data, + nrt_Error * error) +{ + + /* Create a new node with the data, to place on the back */ + nrt_ListNode *node = + nrt_ListNode_construct(this_list->last, NULL, data, error); + + if (!node) + { + return 0; + } + + /* If the last one is set */ + if (this_list->last) + { + + /* Point the (former) last node at our new node */ + /* And, of course, reassign what last means */ + this_list->last = this_list->last->next = node; + } + + /* Otherwise this is the first node */ + else + { + + this_list->first = this_list->last = node; + } + return 1; +} + +NRTAPI(NRT_DATA *) nrt_List_popFront(nrt_List * this_list) +{ + + /* Make sure to NULL init it */ + NRT_DATA *data = NULL; + + /* Get ourselves a pointer to the first link */ + nrt_ListNode *popped = this_list ? this_list->first : NULL; + + /* If it exists, reassign the pointers */ + if (popped) + { + /* If there is more than one node */ + if (this_list->first != this_list->last) + { + /* Reassign the first to the next */ + this_list->first = this_list->first->next; + /* Reset the first link, thereby eliminating popped */ + this_list->first->prev = NULL; + } + /* Otherwise reset the first and the last to NULL pointers */ + else + this_list->first = this_list->last = NULL; + data = popped->data; + nrt_ListNode_destruct(&popped); + } + /* Return the popped item. Deletion is YOUR problem */ + return data; +} + +NRTAPI(NRT_DATA *) nrt_List_popBack(nrt_List * this_list) +{ + NRT_DATA *data = NULL; + + /* Get a pointer to the current last */ + nrt_ListNode *popped = this_list ? this_list->last : NULL; + + /* If we have an element */ + if (popped) + { + /* If there is more than one element */ + if (this_list->last != this_list->first) + { + /* Point the list last node at the previous to last */ + this_list->last = this_list->last->prev; + /* Now eliminate the 'next' and we have shortened our list */ + this_list->last->next = NULL; + } + /* Otherwise, set our list pointers to NULL (we are empty) */ + else + { + this_list->first = this_list->last = NULL; + } + data = popped->data; + nrt_ListNode_destruct(&popped); + } + /* Return the popped node */ + return data; +} + +NRTAPI(nrt_List *) nrt_List_construct(nrt_Error * error) +{ + /* New allocate a list */ + nrt_List *l; + l = (nrt_List *) NRT_MALLOC(sizeof(nrt_List)); + if (!l) + { + /* Initialize the error and return NULL */ + nrt_Error_init(error, NRT_STRERROR(NRT_ERRNO), NRT_CTXT, + NRT_ERR_MEMORY); + return NULL; + } + /* Null-initialize the link pointers */ + l->first = l->last = NULL; + return l; +} + +NRTAPI(nrt_List *) nrt_List_clone(nrt_List * source, NRT_DATA_ITEM_CLONE cloner, + nrt_Error * error) +{ + nrt_List *l = NULL; + if (source) + { + nrt_ListIterator iter = nrt_List_begin(source); + nrt_ListIterator end = nrt_List_end(source); + l = nrt_List_construct(error); + if (!l) + return NULL; + + while (nrt_ListIterator_notEqualTo(&iter, &end)) + { + + /* Foreach item in each list... */ + NRT_DATA *data = nrt_ListIterator_get(&iter); + + /* Use the function pointer to clone the object... */ + NRT_DATA *newData = (NRT_DATA *) cloner(data, error); + if (!newData) + return NULL; + + /* ... and then insert it with the key into the new table */ + if (!nrt_List_pushBack(l, newData, error)) + { + /* destruct the created list. NOTE - there is no way for us to + * destroy the NRT_DATA* chunks that have already been cloned */ + nrt_List_destruct(&l); + return NULL; + } + + nrt_ListIterator_increment(&iter); + } + } + else + { + nrt_Error_initf(error, NRT_CTXT, NRT_ERR_INVALID_OBJECT, + "Trying to clone NULL pointer"); + } + + return l; +} + +NRTAPI(void) nrt_List_destruct(nrt_List ** this_list) +{ + NRT_DATA *data; + if (*this_list) + { + /* Destroy each node in our list. */ + while (!nrt_List_isEmpty(*this_list)) + { + /* Pop one off the back and delete it */ + data = nrt_List_popBack(*this_list); + /* delete it */ + if (data) + NRT_FREE(data); + } + NRT_FREE(*this_list); + *this_list = NULL; + } + +} + +NRTAPI(nrt_ListIterator) nrt_List_begin(nrt_List * list) +{ + nrt_ListIterator list_iterator; + + /* Be ruthless with our assertions */ + assert(list); + list_iterator.current = list->first; + + return list_iterator; +} + +NRTAPI(nrt_ListIterator) nrt_List_at(nrt_List * chain, int i) +{ + nrt_ListIterator list_iterator = nrt_List_begin(chain); + nrt_ListIterator end = nrt_List_end(chain); + int j; + for (j = 0; j < i; j++) + { + if (nrt_ListIterator_equals(&list_iterator, &end)) + { + list_iterator.current = NULL; + break; + } + nrt_ListIterator_increment(&list_iterator); + } + + return list_iterator; +} + +NRTAPI(NRT_BOOL) nrt_ListIterator_equals(nrt_ListIterator * it1, + nrt_ListIterator * it2) +{ + return (it1->current == it2->current); +} + +NRTAPI(NRT_BOOL) nrt_ListIterator_notEqualTo(nrt_ListIterator * it1, + nrt_ListIterator * it2) +{ + return !nrt_ListIterator_equals(it1, it2); +} + +NRTAPI(nrt_ListIterator) nrt_List_end(nrt_List * this_list) +{ + nrt_ListIterator list_iterator; + + /* Silence compiler warnings about unused variables */ + (void)this_list; + + list_iterator.current = NULL; + return list_iterator; +} + +NRTAPI(NRT_DATA *) nrt_List_remove(nrt_List * list, nrt_ListIterator * where) +{ + NRT_DATA *data = NULL; + nrt_ListNode *old = NULL; + nrt_ListNode *new_current = NULL; + + /* Take care of special cases early */ + if (where->current == list->first) + { + data = nrt_List_popFront(list); + *where = nrt_List_begin(list); + } + else if (where->current == list->last) + { + data = nrt_List_popBack(list); + *where = nrt_List_end(list); + + } + else + { + /* Make a pointer to the data right quick */ + data = where->current->data; + + /* Rewire the surrounding elements */ + old = where->current; + new_current = old->next; + + new_current->prev = old->prev; + old->prev->next = new_current; + + /* Reset the iterator to the NEXT */ + where->current = new_current; + + /* Now, destruct the listNode, but not the data */ + nrt_ListNode_destruct(&old); + } + /* Return what we saved */ + + return data; +} + +NRTAPI(NRT_BOOL) nrt_List_move(nrt_List * chain, nrt_Uint32 oldIndex, + nrt_Uint32 newIndex, nrt_Error * error) +{ + nrt_Uint32 listSize = nrt_List_size(chain); + nrt_ListIterator iter; + NRT_DATA *data = NULL; + + /* don't need to check < 0, but in case params change, we'll do it anyway */ + if (oldIndex < 0 || oldIndex == newIndex || oldIndex >= listSize) + { + nrt_Error_init(error, "Invalid list index specified", NRT_CTXT, + NRT_ERR_INVALID_PARAMETER); + return NRT_FAILURE; + } + newIndex = newIndex > listSize || newIndex < 0 ? listSize : newIndex; + + /* first, remove the data from the list */ + iter = nrt_List_at(chain, oldIndex); + data = nrt_List_remove(chain, &iter); + /* next, insert it at the new location */ + iter = nrt_List_at(chain, newIndex); + return nrt_List_insert(chain, iter, data, error); +} + +NRTAPI(NRT_BOOL) nrt_List_insert(nrt_List * list, nrt_ListIterator iter, + NRT_DATA * data, nrt_Error * error) +{ + /* If our iterator is not set, we will insert the data into the back */ + if (!iter.current) + { + /* Push the data onto the back */ + if (!nrt_List_pushBack(list, data, error)) + { + return 0; + } + /* Update the iterator to point at us */ + iter.current = list->last; + } + /* If the iterator is at the first */ + else if (iter.current == list->first) + { + /* Push data onto the front */ + if (!nrt_List_pushFront(list, data, error)) + { + return 0; + } + /* Update the iterator to point at us */ + iter.current = list->first; + } + else + { + + /* Construct a new node and insert it before the current */ + nrt_ListNode *new_node = nrt_ListNode_construct(iter.current->prev, + iter.current, + data, + error); + + /* If an error occurred, the list node captured it */ + if (!new_node) + { + /* Error already populated, go home */ + return 0; + } + + /* Point the iterator at our new node */ + iter.current->prev->next = new_node; + new_node->next->prev = new_node; + iter.current = new_node; + } + return 1; +} + +NRTAPI(void) nrt_ListIterator_increment(nrt_ListIterator * this_iter) +{ + if (this_iter->current) + this_iter->current = this_iter->current->next; +} + +NRTAPI(NRT_DATA *) nrt_ListIterator_get(nrt_ListIterator * this_iter) +{ + /* Lets make sure we are okay */ + assert(this_iter->current); + return this_iter->current->data; +} + +NRTAPI(nrt_Uint32) nrt_List_size(nrt_List * list) +{ + nrt_Uint32 size = 0; + + if (list) + { + nrt_ListIterator iter = nrt_List_begin(list); + nrt_ListIterator end = nrt_List_end(list); + while (nrt_ListIterator_notEqualTo(&iter, &end)) + { + ++size; + nrt_ListIterator_increment(&iter); + } + } + return size; +} + +NRTAPI(NRT_DATA *) nrt_List_get(nrt_List * list, int index, nrt_Error * error) +{ + int i = 0; + if (list) + { + nrt_ListIterator iter = nrt_List_begin(list); + nrt_ListIterator end = nrt_List_end(list); + for (i = 0; i < index && nrt_ListIterator_notEqualTo(&iter, &end); ++i) + nrt_ListIterator_increment(&iter); + if (i == index && nrt_ListIterator_notEqualTo(&iter, &end)) + { + return nrt_ListIterator_get(&iter); + } + else + { + nrt_Error_init(error, "Object not found at index", NRT_CTXT, + NRT_ERR_INVALID_OBJECT); + return NULL; + } + } + else + { + nrt_Error_init(error, "Invalid list -> NULL", NRT_CTXT, + NRT_ERR_INVALID_OBJECT); + return NULL; + } +} diff --git a/modules/c/nrt/source/Pair.c b/modules/c/nrt/source/Pair.c new file mode 100644 index 000000000..c02c3c739 --- /dev/null +++ b/modules/c/nrt/source/Pair.c @@ -0,0 +1,38 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nrt/Pair.h" + +NRTAPI(void) nrt_Pair_init(nrt_Pair * pair, const char *key, NRT_DATA * data) +{ + size_t len = strlen(key); + pair->key = (char *) NRT_MALLOC(len + 1); + /* Help, we have an unchecked malloc here! */ + pair->key[len] = 0; + strcpy(pair->key, key); + pair->data = data; +} + +NRTAPI(void) nrt_Pair_copy(nrt_Pair * dst, nrt_Pair * src) +{ + nrt_Pair_init(dst, src->key, src->data); +} diff --git a/modules/c/nrt/source/SyncIrix.c b/modules/c/nrt/source/SyncIrix.c new file mode 100644 index 000000000..971b22deb --- /dev/null +++ b/modules/c/nrt/source/SyncIrix.c @@ -0,0 +1,52 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nrt/Debug.h" +#include "nrt/Sync.h" + +NRT_CXX_GUARD +#if defined(__sgi) +NRTPROT(void) nrt_Mutex_lock(nrt_Mutex * m) +{ + nrt_Debug_flogf(stdout, "***Locking Mutex*** [sgi]\n"); + while (!__compare_and_swap(m, 0, 1)); +} + +NRTPROT(void) nrt_Mutex_unlock(nrt_Mutex * m) +{ + nrt_Debug_flogf(stdout, "***Unlocking Mutex***\n"); + *m = 0; +} + +NRTPROT(void) nrt_Mutex_init(nrt_Mutex * m) +{ + nrt_Debug_flogf(stdout, "***Initializing Mutex*** [sgi]\n"); + *m = 0; +} + +NRTPROT(void) nrt_Mutex_delete(nrt_Mutex * m) +{ + nrt_Debug_flogf(stdout, "***Destroy Mutex*** [sgi] (empty)\n"); +} +#endif + +NRT_CXX_ENDGUARD diff --git a/modules/c/nrt/source/SyncUnix.c b/modules/c/nrt/source/SyncUnix.c new file mode 100644 index 000000000..ed1ecb433 --- /dev/null +++ b/modules/c/nrt/source/SyncUnix.c @@ -0,0 +1,57 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nrt/Debug.h" +#include "nrt/Sync.h" + +NRT_CXX_GUARD +#if !defined(WIN32) && !defined(__sgi) +NRTPROT(void) nrt_Mutex_lock(nrt_Mutex * m) +{ + nrt_Debug_flogf(stdout, "***Locking Mutex***\n"); + pthread_mutex_lock((pthread_mutex_t *) m); +} + +NRTPROT(void) nrt_Mutex_unlock(nrt_Mutex * m) +{ + nrt_Debug_flogf(stdout, "***Unlocking Mutex***\n"); + pthread_mutex_unlock((pthread_mutex_t *) m); +} + +NRTPROT(void) nrt_Mutex_init(nrt_Mutex * m) +{ + nrt_Debug_flogf(stdout, "***Initializing Mutex***\n"); + pthread_mutex_init(m, NULL); +} + +NRTPROT(void) nrt_Mutex_delete(nrt_Mutex * m) +{ + nrt_Debug_flogf(stdout, "***Trying to Destroy Mutex***\n"); + if (m) + { + pthread_mutex_destroy((pthread_mutex_t *) m); + nrt_Debug_flogf(stdout, "***Destroyed Mutex***\n"); + } +} +#endif + +NRT_CXX_ENDGUARD diff --git a/modules/c/nrt/source/SyncWin32.c b/modules/c/nrt/source/SyncWin32.c new file mode 100644 index 000000000..8e3cb6279 --- /dev/null +++ b/modules/c/nrt/source/SyncWin32.c @@ -0,0 +1,67 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nrt/Sync.h" + +NRT_CXX_GUARD +#if defined(WIN32) +NRTPROT(void) nrt_Mutex_lock(nrt_Mutex * m) +{ + LPCRITICAL_SECTION lpCriticalSection = (LPCRITICAL_SECTION) (*m); + /* OpenMutex(MUTEX_ALL_ACCESS, FALSE, "PluginRegistry::getMutex()"); */ + EnterCriticalSection(lpCriticalSection); +} + +NRTPROT(void) nrt_Mutex_unlock(nrt_Mutex * m) +{ + /* ReleaseMutex((HANDLE)m); */ + LPCRITICAL_SECTION lpCriticalSection = (LPCRITICAL_SECTION) (*m); + LeaveCriticalSection(lpCriticalSection); +} + +NRTPROT(void) nrt_Mutex_init(nrt_Mutex * m) +{ + + LPCRITICAL_SECTION lpCriticalSection = + (LPCRITICAL_SECTION) NRT_MALLOC(sizeof(CRITICAL_SECTION)); + /* nrt_Debug_flogf("***Initializing Mutex***\n"); */ + InitializeCriticalSection(lpCriticalSection); + /**m = CreateMutex(NULL, TRUE, "PluginRegistry::getMutex()");*/ + /* if (*m && GetLastError() == ERROR_ALREADY_EXISTS) + * OpenMutex(MUTEX_ALL_ACCESS, FALSE, "PluginRegistry::getMutex()"); */ + *m = (nrt_Mutex) lpCriticalSection; +} + +NRTPROT(void) nrt_Mutex_delete(nrt_Mutex * m) +{ + LPCRITICAL_SECTION lpCriticalSection = (LPCRITICAL_SECTION) (*m); + /* nrt_Debug_flogf("***Trying to Destroy Mutex***\n"); */ + if (lpCriticalSection) + { + DeleteCriticalSection(lpCriticalSection); + /* nrt_Debug_flogf("***Destroyed Mutex***\n"); */ + NRT_FREE(lpCriticalSection); + } +} +#endif + +NRT_CXX_ENDGUARD diff --git a/modules/c/nrt/source/System.c b/modules/c/nrt/source/System.c new file mode 100644 index 000000000..18ecc07cb --- /dev/null +++ b/modules/c/nrt/source/System.c @@ -0,0 +1,82 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include "nrt/System.h" + +NRTPROT(nrt_Uint16) nrt_System_swap16(nrt_Uint16 ins) +{ + nrt_Uint16 outs; + unsigned char *ibytep = (unsigned char *) &ins; + unsigned char *obytep = (unsigned char *) &outs; + obytep[1] = ibytep[0]; + obytep[0] = ibytep[1]; + return outs; +} + +NRTPROT(nrt_Uint32) nrt_System_swap32(nrt_Uint32 inl) +{ + nrt_Uint32 outl; + unsigned char *ibytep = (unsigned char *) &inl; + unsigned char *obytep = (unsigned char *) &outl; + obytep[3] = ibytep[0]; + obytep[2] = ibytep[1]; + obytep[1] = ibytep[2]; + obytep[0] = ibytep[3]; + return outl; +} + +NRTPROT(nrt_Uint64) nrt_System_swap64c(nrt_Uint64 inl) +{ + nrt_Uint64 outl; + const unsigned char* const ibytep = (const unsigned char* )&inl; + unsigned char* const obytep = (unsigned char* )&outl; + + /* 4 byte real */ + obytep[7] = ibytep[4]; + obytep[6] = ibytep[5]; + obytep[5] = ibytep[6]; + obytep[4] = ibytep[7]; + + /* 4 byte imaginary */ + obytep[3] = ibytep[0]; + obytep[2] = ibytep[1]; + obytep[1] = ibytep[2]; + obytep[0] = ibytep[3]; + return outl; +} + +NRTPROT(nrt_Uint64) nrt_System_swap64(nrt_Uint64 inl) +{ + nrt_Uint64 outl; + unsigned char *ibytep = (unsigned char *) &inl; + unsigned char *obytep = (unsigned char *) &outl; + + obytep[7] = ibytep[0]; + obytep[6] = ibytep[1]; + obytep[5] = ibytep[2]; + obytep[4] = ibytep[3]; + obytep[3] = ibytep[4]; + obytep[2] = ibytep[5]; + obytep[1] = ibytep[6]; + obytep[0] = ibytep[7]; + return outl; +} diff --git a/modules/c/nrt/source/Tree.c b/modules/c/nrt/source/Tree.c new file mode 100644 index 000000000..537729d81 --- /dev/null +++ b/modules/c/nrt/source/Tree.c @@ -0,0 +1,282 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; + * If not, see . + * + */ + +#include "nrt/Tree.h" + +NRTPRIV(NRT_BOOL) preOrder(nrt_TreeNode * node, NRT_TREE_TRAVERSER onNode, + NRT_DATA * userData, int depth, nrt_Error * error) +{ + nrt_ListIterator where, end; + nrt_List *list; + assert(node); + + list = node->children; + where = nrt_List_begin(list); + end = nrt_List_end(list); + if (!(*onNode) (node, userData, depth, error)) + return NRT_FAILURE; + + while (nrt_ListIterator_notEqualTo(&where, &end)) + { + nrt_TreeNode *candidate = (nrt_TreeNode *) nrt_ListIterator_get(&where); + if (!preOrder(candidate, onNode, userData, depth + 1, error)) + return NRT_FAILURE; + nrt_ListIterator_increment(&where); + } + + return NRT_SUCCESS; +} + +NRTPRIV(NRT_BOOL) postOrder(nrt_TreeNode * node, NRT_TREE_TRAVERSER onNode, + NRT_DATA * userData, int depth, nrt_Error * error) +{ + nrt_ListIterator where, end; + nrt_List *list; + assert(node); + + list = node->children; + where = nrt_List_begin(list); + end = nrt_List_end(list); + + while (nrt_ListIterator_notEqualTo(&where, &end)) + { + nrt_TreeNode *candidate = (nrt_TreeNode *) nrt_ListIterator_get(&where); + + if (!postOrder(candidate, onNode, userData, depth + 1, error)) + return NRT_FAILURE; + + nrt_ListIterator_increment(&where); + } + + return (*onNode) (node, userData, depth, error); + +} + +NRTAPI(nrt_TreeNode *) nrt_TreeNode_construct(NRT_DATA * data, + nrt_Error * error) +{ + nrt_TreeNode *node = (nrt_TreeNode *) NRT_MALLOC(sizeof(nrt_TreeNode)); + + node->parent = NULL; + + if (node == NULL) + { + /* Init the error with the string value of errno */ + nrt_Error_init(error, NRT_STRERROR(NRT_ERRNO), NRT_CTXT, + NRT_ERR_MEMORY); + /* Return if we have a problem */ + return NULL; + } + /* printf("Constructed node: %p\n", node); */ + /* This is a reference (see List.c or comments in Tree.h) */ + node->data = data; + + node->children = nrt_List_construct(error); + if (!node->children) + { + /* There goes the show! */ + nrt_TreeNode_destruct(&node); + } + + /* Return the new node */ + return node; + +} + +NRTPRIV(void) killNodes(nrt_TreeNode * node) +{ + nrt_ListIterator where, end; + nrt_List *list; + + list = node->children; + /* First thing we need to do is walk the list and find the child */ + where = nrt_List_begin(list); + end = nrt_List_end(list); + + while (nrt_ListIterator_notEqualTo(&where, &end)) + { + nrt_TreeNode *child = (nrt_TreeNode *) nrt_ListIterator_get(&where); + if (child != node) + { + nrt_TreeNode_destruct(&child); + } + nrt_ListIterator_increment(&where); + } + NRT_FREE(node); + /* printf("Destroyed node: %p\n", node); */ +} + +NRTAPI(void) nrt_TreeNode_destruct(nrt_TreeNode ** node) +{ + + if (*node) + { + + killNodes(*node); + *node = NULL; + } + +} + +NRTAPI(NRT_BOOL) nrt_TreeNode_addChild(nrt_TreeNode * node, + nrt_TreeNode * child, nrt_Error * error) +{ + assert(node); + assert(child); + child->parent = node; + /* printf("Adding %s to %s\n", (char*)child->data, (char*)node->data); */ + + return nrt_List_pushBack(node->children, child, error); +} + +NRTAPI(NRT_BOOL) nrt_TreeNode_hasChildren(nrt_TreeNode * node) +{ + assert(node); + return nrt_List_isEmpty(node->children); + +} + +NRTAPI(NRT_BOOL) nrt_TreeNode_removeChild(nrt_TreeNode * node, + nrt_TreeNode * child) +{ + nrt_ListIterator where, end; + nrt_List *list; + int found = 0; + assert(node); + assert(child); + + list = node->children; + + /* First thing we need to do is walk the list and find the child */ + where = nrt_List_begin(list); + end = nrt_List_end(list); + + while (nrt_ListIterator_notEqualTo(&where, &end)) + { + nrt_TreeNode *candidate = (nrt_TreeNode *) nrt_ListIterator_get(&where); + if (candidate == node) + { + found = 1; + break; + } + nrt_ListIterator_increment(&where); + } + + /* Note, if there are multiple of the same node in this tree, we arent + * currently accounting for that, so if you knew that you had it, you would + * * * * * * have to call this function repeatedly, e.g., while + * (nrt_TreeNode_remove(tree, node)); */ + + /* Then we simply remove that element */ + if (found) + { + child->parent = NULL; + nrt_List_remove(list, &where); + } + return found; + +} + +NRTAPI(nrt_TreeNode *) nrt_TreeNode_clone(nrt_TreeNode * source, + NRT_DATA_ITEM_CLONE cloner, + nrt_Error * error) +{ + nrt_ListIterator where, end; + nrt_List *list; + + nrt_TreeNode *clone = nrt_TreeNode_construct(NULL, error); + assert(clone); + clone->data = (*(cloner)) (source->data, error); + + list = source->children; + + /* First thing we need to do is walk the list and find the child */ + where = nrt_List_begin(list); + end = nrt_List_end(list); + + while (nrt_ListIterator_notEqualTo(&where, &end)) + { + nrt_TreeNode *sourceChild = + (nrt_TreeNode *) nrt_ListIterator_get(&where); + + nrt_TreeNode *cloneChild = + nrt_TreeNode_clone(sourceChild, cloner, error); + + nrt_TreeNode_addChild(clone, cloneChild, error); + + nrt_ListIterator_increment(&where); + } + return clone; +} + +NRTAPI(nrt_Tree *) nrt_Tree_construct(nrt_TreeNode * root, nrt_Error * error) +{ + nrt_Tree *tree; + + tree = (nrt_Tree *) NRT_MALLOC(sizeof(nrt_Tree)); + if (!tree) + { + /* Initialize the error and return NULL */ + nrt_Error_init(error, NRT_STRERROR(NRT_ERRNO), NRT_CTXT, + NRT_ERR_MEMORY); + return NULL; + } + tree->root = root; + return tree; + +} + +NRTAPI(void) nrt_Tree_destruct(nrt_Tree ** tree) +{ + if (*tree) + { + nrt_TreeNode *root = (*tree)->root; + nrt_TreeNode_destruct(&root); + NRT_FREE(*tree); + *tree = NULL; + } + +} + +NRTAPI(NRT_BOOL) nrt_Tree_walk(nrt_Tree * tree, NRT_TREE_TRAVERSER onNode, + int traversalOrder, NRT_DATA * userData, + nrt_Error * error) +{ + if (traversalOrder == NRT_PRE_ORDER) + return preOrder(tree->root, onNode, userData, 0, error); + return postOrder(tree->root, onNode, userData, 0, error); + +} + +NRTAPI(nrt_Tree *) nrt_Tree_clone(nrt_Tree * source, NRT_DATA_ITEM_CLONE cloner, + nrt_Error * error) +{ + nrt_TreeNode *root; + assert(source); + assert(source->root); + root = nrt_TreeNode_clone(source->root, cloner, error); + if (!root) + return NULL; + + return nrt_Tree_construct(root, error); + +} diff --git a/modules/c/nrt/source/Utils.c b/modules/c/nrt/source/Utils.c new file mode 100644 index 000000000..3ec7fdfb3 --- /dev/null +++ b/modules/c/nrt/source/Utils.c @@ -0,0 +1,499 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, + * see . + * + */ + +#include "nrt/Utils.h" + +NRTAPI(nrt_List *) nrt_Utils_splitString(char *str, unsigned int max, + nrt_Error * error) +{ + unsigned int count = 0; + nrt_List *parts; + char *op, *cur, *end; + size_t strLen; + + parts = nrt_List_construct(error); + if (!parts) + return NULL; + + strLen = strlen(str); + end = str + strLen; + + op = str; + + if (max == 1) + { + char *val = (char* )NRT_MALLOC(strLen + 1); + if (!val) + { + nrt_Error_init(error, NRT_STRERROR(NRT_ERRNO), NRT_CTXT, + NRT_ERR_MEMORY); + return NULL; + } + memset(val, 0, strLen + 1); + memcpy(val, str, strLen); + nrt_List_pushBack(parts, val, error); + } + else + { + /* strtok is not thread safe */ + while (op < end) + { + char *val = NULL; + size_t sz; + /* skip past white space */ + while (isspace(*op) && op < end) + ++op; + cur = op; + + while (!isspace(*op) && op < end) + ++op; + + if (cur == op) + break; + + sz = op - cur; + val = (char* )NRT_MALLOC(sz + 1); + if (!val) + { + nrt_Error_init(error, NRT_STRERROR(NRT_ERRNO), NRT_CTXT, + NRT_ERR_MEMORY); + return NULL; + } + memset(val, 0, sz + 1); + memcpy(val, cur, sz); + nrt_List_pushBack(parts, val, error); + count++; + + /* check the count limit */ + if (max != 0 && count == (max - 1) && op < end) + { + /* push on the rest of the string - skip spaces first */ + while (isspace(*op) && op < end) + ++op; + + if (op < end) + { + sz = end - op; + val = (char* )NRT_MALLOC(sz + 1); + if (!val) + { + nrt_Error_init(error, NRT_STRERROR(NRT_ERRNO), NRT_CTXT, + NRT_ERR_MEMORY); + return NULL; + } + memset(val, 0, sz + 1); + memcpy(val, op, sz); + nrt_List_pushBack(parts, val, error); + } + break; + } + } + } + + return parts; +} + +NRTAPI(NRT_BOOL) nrt_Utils_isNumeric(char *str) +{ + char *sp = NULL; + if (!str) + return 0; + sp = str + strlen(str); + if (sp <= str) + return 0; + + do + { + if (!isdigit(*(--sp))) + return 0; + } + while (sp > str); + return 1; +} + +NRTAPI(NRT_BOOL) nrt_Utils_isAlpha(char *str) +{ + char *sp = NULL; + if (!str) + return 0; + sp = str + strlen(str); + if (sp <= str) + return 0; + + do + { + if (!isalpha(*(--sp))) + return 0; + } + while (sp > str); + return 1; +} + +NRTAPI(NRT_BOOL) nrt_Utils_isBlank(char *str) +{ + char *sp = NULL; + if (!str) + return 1; + sp = str + strlen(str); + if (sp <= str) + return 1; + + do + { + if (!isspace(*(--sp))) + return 0; + } + while (sp > str); + return 1; +} + +NRTAPI(void) nrt_Utils_trimString(char *str) +{ + size_t len; /* Length of the string */ + char* strp; /* Pointer into the string */ + size_t i; + + /* strip the end */ + strp = str + (strlen(str) - 1); + while (isspace(*strp) && strp != str) + *(strp--) = '\0'; + + /* strip the front */ + len = strlen(str); + strp = str; + for (i = 0; i < len && isspace(*strp); ++i) + strp++; + if (strp != str) + { + len = str + len - strp; + memmove(str, strp, len); + str[len] = '\0'; + } + return; +} + +NRTPROT(void) nrt_Utils_replace(char *str, char oldValue, char newValue) +{ + char *p; + while ((p = strchr(str, oldValue)) != NULL) + { + *p = newValue; + } + +} + +NRTAPI(void) nrt_Utils_baseName(char *base, const char *fullName, + const char *extension) +{ + size_t i, begin = 0; + const size_t len = strlen(fullName); + size_t end = len; + const char *p = strstr(fullName, extension); + for (i = 0; i < len; i++) + { + if (*(fullName + i) == '/' || *(fullName + i) == '\\') + begin = i + 1; + + if (fullName + i == p) + end = i - 1; + } + memcpy(base, &fullName[begin], end - begin + 1); + base[end - begin + 1] = '\0'; +} + +NRTAPI(NRT_BOOL) nrt_Utils_parseDecimalString(char *d, double *decimal, + nrt_Error * error) +{ + /* +-dd.ddd or += ddd.ddd */ + int degreeOffset = 0; + const size_t len = strlen(d); + const char sign = d[0]; + if (len == 7) + { + degreeOffset = 2; + } + else if (len == 8) + { + degreeOffset = 3; + } + else + { + nrt_Error_initf(error, NRT_CTXT, NRT_ERR_INVALID_PARAMETER, + "Invalid decimal string: '%s'. Should be +-dd.ddd or +-ddd.ddd", + d); + return NRT_FAILURE; + } + /* Now replace all spaces */ + nrt_Utils_replace(d, ' ', '0'); + *decimal = atof(&(d[1])); + + if (sign == '-') + { + *decimal *= -1; + } + + return NRT_SUCCESS; +} + +NRTAPI(double) nrt_Utils_getCurrentTimeMillis() +{ + double millis = 0; +#if defined(__POSIX) && defined(USE_CLOCK_GETTIME) + struct timespec now; + clock_gettime(CLOCK_REALTIME, &now); + millis = (now.tv_sec + 1.0e-9 * now.tv_nsec) * 1000; +#elif defined(HAVE_SYS_TIME_H) + struct timeval now; + gettimeofday(&now, NULL); + millis = (now.tv_sec + 1.0e-6 * now.tv_usec) * 1000; +#elif defined(WIN32) + // Getting time twice may be inefficient but is quicker + // than converting the SYSTEMTIME structure into milliseconds + // We could add an additional flag here if the user + // does not need millisecond accuracy + SYSTEMTIME now; + GetLocalTime(&now); + millis = (double) time(NULL) * 1000 + now.wMilliseconds; +#else + millis = (double) time(NULL) * 1000; +#endif + return millis; +} + +NRTAPI(int) nrt_Utils_strncasecmp(char *s1, char *s2, size_t n) +{ + if (n == 0) + return 0; + + while (n-- != 0 && tolower(*s1) == tolower(*s2)) + { + if (n == 0 || *s1 == '\0' || *s2 == '\0') + break; + s1++; + s2++; + } + return tolower(*(unsigned char *) s1) - tolower(*(unsigned char *) s2); +} + +NRTAPI(void) nrt_Utils_decimalToGeographic(double decimal, int *degrees, + int *minutes, double *seconds) +{ + double remainder; + *degrees = (int) decimal; + remainder = fabs(decimal - (double) *degrees) * 60.0; + *minutes = (int) remainder; + *seconds = fabs(remainder - (double) *minutes) * 60.0; + +} + +NRTAPI(double) nrt_Utils_geographicToDecimal(int degrees, int minutes, + double seconds) +{ + double decimal = fabs((double)degrees); + decimal += ((double) minutes / 60.0); + decimal += (seconds / 3600.0); + + if (degrees < 0) + { + decimal *= -1; + } + + return decimal; +} + +NRTAPI(NRT_BOOL) nrt_Utils_parseGeographicString(char *dms, int *degrees, + int *minutes, double *seconds, + nrt_Error * error) +{ + int degreeOffset = 0; + const size_t len = strlen(dms); + char dir; + + char d[4]; + char m[3]; + char s[3]; + + /* ddmmssX or dddmmssY */ + if (len == 7) + { + degreeOffset = 2; + } + else if (len == 8) + { + degreeOffset = 3; + } + else + { + nrt_Error_initf(error, NRT_CTXT, NRT_ERR_INVALID_PARAMETER, + "Invalid decimal string: %s. Should be ddmmssX or dddmmssY", + dms); + return NRT_FAILURE; + } + dir = dms[len - 1]; + if (dir != 'N' && dir != 'S' && dir != 'E' && dir != 'W') + { + nrt_Error_initf(error, NRT_CTXT, NRT_ERR_INVALID_PARAMETER, + "Invalid direction: %s. Should be [NSEW]", dms); + return NRT_FAILURE; + } + + /* Now replace all spaces */ + nrt_Utils_replace(dms, ' ', '0'); + + /* Now get the corners out as geographic coords */ + d[degreeOffset] = 0; + memcpy(d, dms, degreeOffset); + + memcpy(m, &dms[degreeOffset], 2); + m[2] = 0; + + memcpy(s, &dms[degreeOffset + 2], 2); + s[2] = 0; + + *degrees = NRT_ATO32(d); + *minutes = NRT_ATO32(m); + *seconds = (double) NRT_ATO32(s); + + if ((degreeOffset == 2 && dir == 'S') || (degreeOffset == 3 && dir == 'W')) + { + *degrees *= -1; + } + + return NRT_SUCCESS; +} + +NRTAPI(char) nrt_Utils_cornersTypeAsCoordRep(nrt_CornersType type) +{ + char cornerRep = ' '; + + switch (type) + { + case NRT_CORNERS_UTM: + cornerRep = 'U'; + break; + + case NRT_CORNERS_UTM_UPS_S: + cornerRep = 'S'; + break; + + case NRT_CORNERS_UTM_UPS_N: + cornerRep = 'N'; + break; + + case NRT_CORNERS_GEO: + cornerRep = 'G'; + break; + + case NRT_CORNERS_DECIMAL: + cornerRep = 'D'; + break; + default: + break; + } + return cornerRep; +} + +NRTPROT(void) nrt_Utils_geographicLatToCharArray(int degrees, int minutes, + double seconds, char *buffer7) +{ + char dir = 'N'; + if (degrees < 0) + { + dir = 'S'; + degrees *= -1; + } + + /* Round seconds. */ + seconds += 0.5; + + /* Ensure seconds and minutes are still within valid range. */ + if (seconds >= 60.0) + { + seconds -= 60.0; + + if (++minutes >= 60) + { + minutes -= 60; + ++degrees; + } + } + + NRT_SNPRINTF(buffer7, 8, "%02d%02d%02d%c", degrees, minutes, + (int) seconds, dir); +} + +NRTPROT(void) nrt_Utils_geographicLonToCharArray(int degrees, int minutes, + double seconds, char *buffer8) +{ + char dir = 'E'; + if (degrees < 0) + { + dir = 'W'; + degrees *= -1; + } + + /* Round seconds. */ + seconds += 0.5; + + /* Ensure seconds and minutes are still within valid range. */ + if (seconds >= 60.0) + { + seconds -= 60.0; + + if (++minutes >= 60) + { + minutes -= 60; + ++degrees; + } + } + + NRT_SNPRINTF(buffer8, 9, "%03d%02d%02d%c", degrees, minutes, + (int) seconds, dir); +} + +NRTPROT(void) nrt_Utils_decimalLatToCharArray(double decimal, char *buffer7) +{ + NRT_SNPRINTF(buffer7, 8, "%+07.3f", decimal); +} + +NRTPROT(void) nrt_Utils_decimalLonToCharArray(double decimal, char *buffer8) +{ + NRT_SNPRINTF(buffer8, 9, "%+08.3f", decimal); +} + +NRTPROT(void) nrt_Utils_decimalLatToGeoCharArray(double decimal, char *buffer7) +{ + int d, m; + double s; + + nrt_Utils_decimalToGeographic(decimal, &d, &m, &s); + nrt_Utils_geographicLatToCharArray(d, m, s, buffer7); +} + +NRTPROT(void) nrt_Utils_decimalLonToGeoCharArray(double decimal, char *buffer8) +{ + int d, m; + double s; + + nrt_Utils_decimalToGeographic(decimal, &d, &m, &s); + nrt_Utils_geographicLonToCharArray(d, m, s, buffer8); +} diff --git a/modules/c/nrt/source/wscript_build b/modules/c/nrt/source/wscript_build new file mode 100644 index 000000000..da72eca80 --- /dev/null +++ b/modules/c/nrt/source/wscript_build @@ -0,0 +1,33 @@ +# encoding: utf-8 + +import os, glob, re +import Params + +ENV = bld.m_allenvs['default'] +APPNAME = ENV['APPNAME'] +VERSION = ENV['VERSION'] +LIB_NAME = APPNAME +INCLUDES = ['../include/'] +SOURCES = [os.path.split(p)[1] for p in glob.glob(os.path.join(bld.m_curdirnode.abspath(), '*.c'))] + +if 'SOURCE_FILTER' in ENV: + sourceFilter = re.compile(ENV['SOURCE_FILTER'], re.I) + filtered = [] + for s in SOURCES: + if sourceFilter.match(s) == None: + filtered.append(s) + SOURCES = filtered + +# objects +obj = bld.create_obj('cc', 'objects') +obj.source = SOURCES +obj.includes = INCLUDES +obj.target = "%s-objects" % APPNAME + +# static library +obj = bld.create_obj('cc', 'staticlib') +obj.name = '%s-static' % APPNAME +obj.target = '%s-c' % LIB_NAME +obj.env = ENV +obj.add_objects = "%s-objects" % APPNAME +obj.uselib = APPNAME diff --git a/modules/c/nrt/tests/verify/mem_sane.pl b/modules/c/nrt/tests/verify/mem_sane.pl new file mode 100755 index 000000000..5983bfad6 --- /dev/null +++ b/modules/c/nrt/tests/verify/mem_sane.pl @@ -0,0 +1,80 @@ +#!/usr/bin/perl -w + +#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# +#_____M____E____M_______S____A____N____E____.____P____L____# +# This program will check a memory trace from a nitf # +# library run. The nitf library must have been compiled # +# with NITF_DEBUG defined, otherwise no memory trace can # +# be generated. # +# # +# The usage for the program is quite simple. After you # +# do a run, the program will dump out a file named # +# memory_trace. or something along those lines. # +# You should run this program with that trace as an arg. # +# # +# (perl) mem_sane.pl # +#__________________________________________________________# + +# Make sure the args are right +@ARGV == 1 or die "Usage $0 "; + +# The name of the trace +my $mem = $ARGV[0]; + +# A hash of info about how the memory was allocated +# The key is the address which was malloc'ed +my %mem_info; + +# Open the trace or die +open MEM, $mem or die "Could not open memory trace \"$mem\""; + +# Scan the trace... +while () { + + # Here is where we allocated + if (/^\tMALLOC\t(\S+)\t([0-9]+)\t(\S+)\t([0-9]+)/) { + $mem_info{$1}[0] = $2; + $mem_info{$1}[1] = $3; + $mem_info{$1}[2] = $4; + } + # Check if there is a corresponding deletion + elsif (/^REQUEST: free\t\[(\S+)\]/) { + + # If it doesnt exist, usually that just means that NITF_MALLOC wasnt + # used to malloc it, but NITF_FREE was + # that is usually not a problem + if ( ! exists $mem_info{$1} ) + { + print "Warning: Deleting unknown memory at $1\n"; + print "\t(This could be the result of a hash adopting which is OK)\n"; + my $questionable = ; + if ($questionable =~ /\tFREE\t(\S+)\t([0-9]+)/) + { + print "\tThe questionable free was performed in file \"$1\" at line $2\n"; + } + else + { + print "Warning: got out of sync. This is a bug. Sorry\n"; + } + print "\n"; + } + # If there IS a corresponding free, delete this from the hash + # of unresolved values + else + { + delete $mem_info{$1}; + } + } + +} +# Print all of the leftover unfreed values +foreach my $loc ( keys %mem_info ) { + my $size = $mem_info{ $loc }[0]; + my $file = $mem_info{ $loc }[1]; + my $line = $mem_info{ $loc }[2]; + print "Unfreed: [$loc]\n"; + print "\tNumber of bytes [$size]\n"; + print "\tAllocated in file \"$file\" at line [$line]\n\n"; +} + +close MEM; diff --git a/modules/c/nrt/unittests/Test.h b/modules/c/nrt/unittests/Test.h new file mode 100644 index 000000000..dd9bd5c9a --- /dev/null +++ b/modules/c/nrt/unittests/Test.h @@ -0,0 +1,84 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#ifndef __TEST_H__ +#define __TEST_H__ + +#ifdef __cplusplus + +#include +#include + +#define CHECK(X) X(std::string(#X)); std::cout << #X << ": PASSED" << std::endl +#define TEST_ASSERT(X) if (!(X)) { die_printf("%s (%s,%s,%d): FAILED: Value should not be NULL\n", testName.c_str(), __FILE__, __FUNC__, __LINE__) } +#define TEST_ASSERT_NULL(X) if ((X) != NULL) { die_printf("%s (%s,%s,%d): FAILED: Value should be NULL\n", testName.c_str(), __FILE__, __FUNC__, __LINE__) } +#define TEST_ASSERT_EQ(X1, X2) if ((X1) != (X2)) { die_printf("%s (%s,%s,%d): FAILED: Recv'd %s, Expected %s\n", testName.c_str(), __FILE__, __FUNC__, __LINE__, str::toString(X1).c_str(), str::toString(X2).c_str()) } +#define TEST_ASSERT_ALMOST_EQ(X1, X2) if (fabs((X1) - (X2)) > std::numeric_limits::epsilon()) { die_printf("%s (%s,%s,%d): FAILED: Recv'd %s, Expected %s\n", testName.c_str(), __FILE__, __FUNC__, __LINE__, str::toString(X1).c_str(), str::toString(X2).c_str()) } +#define TEST_CASE(X) void X(std::string testName) + +#else + +# include +# include +# include + +/* Negotiate the 'context' */ +#define TEST_FILE __FILE__ +#define TEST_LINE __LINE__ +#if defined(__GNUC__) +# define TEST_FUNC __PRETTY_FUNCTION__ +#elif __STDC_VERSION__ < 199901 +# define TEST_FUNC "unknown function" +#else /* Should be c99 */ +# define TEST_FUNC __func__ +#endif + +#define CHECK(X) X(#X); fprintf(stderr, "%s : PASSED\n", #X); +#define CHECK_ARGS(X) X(#X,argc,argv); fprintf(stderr, "%s : PASSED\n", #X); +#define TEST_ASSERT(X) if (!(X)) { \ + fprintf(stderr, "%s (%s,%s,%d) : FAILED: Value should not be NULL\n", testName, TEST_FILE, TEST_FUNC, TEST_LINE); \ + exit(EXIT_FAILURE); \ +} +#define TEST_ASSERT_NULL(X) if ((X) != NULL) { \ + fprintf(stderr, "%s (%s,%s,%d) : FAILED: Value should be NULL\n", testName, TEST_FILE, TEST_FUNC, TEST_LINE); \ + exit(EXIT_FAILURE); \ +} +#define TEST_ASSERT_EQ_STR(X1, X2) if (strcmp((X1), (X2)) != 0) { \ + fprintf(stderr, "%s (%s,%s,%d) : FAILED: Recv'd %s, Expected %s\n", testName, TEST_FILE, TEST_FUNC, TEST_LINE, X1, X2); \ + exit(EXIT_FAILURE); \ +} +#define TEST_ASSERT_EQ_INT(X1, X2) if ((X1) != (X2)) { \ + fprintf(stderr, "%s (%s,%s,%d) : FAILED: Recv'd %d, Expected %d\n", testName, TEST_FILE, TEST_FUNC, TEST_LINE, (int)X1, (int)X2); \ + exit(EXIT_FAILURE); \ +} +/* TODO use epsilon for comparing floating points */ +#define TEST_ASSERT_EQ_FLOAT(X1, X2) if (fabs((X1) - (X2)) > .0000001f) { \ + fprintf(stderr, "%s (%s,%s,%d) : FAILED: Recv'd %f, Expected %f\n", testName, TEST_FILE, TEST_FUNC, TEST_LINE, X1, X2); \ + exit(EXIT_FAILURE); \ +} + +#define TEST_CASE(X) void X(const char* testName) +#define TEST_CASE_ARGS(X) void X(const char* testName, int argc, char **argv) + +#endif + +#endif diff --git a/modules/c/nrt/unittests/test_core_values.c b/modules/c/nrt/unittests/test_core_values.c new file mode 100644 index 000000000..1748b4a8a --- /dev/null +++ b/modules/c/nrt/unittests/test_core_values.c @@ -0,0 +1,71 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include +#include "Test.h" + +TEST_CASE(testCoreValues) +{ + TEST_ASSERT(sizeof(nrt_Uint8) == 1); + TEST_ASSERT(sizeof(nrt_Uint16) == 2); + TEST_ASSERT(sizeof(nrt_Uint32) == 4); + TEST_ASSERT(sizeof(nrt_Uint64) == 8); + + TEST_ASSERT(sizeof(nrt_Int8) == 1); + TEST_ASSERT(sizeof(nrt_Int16) == 2); + TEST_ASSERT(sizeof(nrt_Int32) == 4); + TEST_ASSERT(sizeof(nrt_Int64) == 8); + + if (sizeof(long) == 4) + { + const char *ok = "2147483647"; + const char *bad = "2147483648"; + /* Test our assertions for atol, format */ + + printf("A long is 4 bytes\n"); + printf("Ok: (str: %s) [%ld]\n", ok, atol(ok)); + printf("Bad: (str: %s) [%ld]\n", bad, atol(bad)); + + printf("As long long\n"); + printf("Ok: (str: %s) [%lld]\n", ok, NRT_ATO64(ok)); + printf("Bad: (str: %s) [%lld]\n", bad, NRT_ATO64(bad)); + + } + else if (sizeof(long) == 8) + { + const char *ok = "9223372036854775807"; + const char *bad = "9223372036854775808"; + printf("A long is 8 bytes\n"); + printf("Ok: (str: %s) [%ld]\n", ok, atol(ok)); + printf("Bad: (str: %s) [%ld]\n", bad, atol(bad)); + + printf("As long long\n"); + printf("Ok: (str: %s) [%lld]\n", ok, NRT_ATO64(ok)); + printf("Bad: (str: %s) [%lld]\n", bad, NRT_ATO64(bad)); + } +} + +int main(int argc, char **argv) +{ + CHECK(testCoreValues); + return 0; +} diff --git a/modules/c/nrt/unittests/test_list.c b/modules/c/nrt/unittests/test_list.c new file mode 100644 index 000000000..951862219 --- /dev/null +++ b/modules/c/nrt/unittests/test_list.c @@ -0,0 +1,182 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include +#include "Test.h" + +TEST_CASE(testCreate) +{ + nrt_Error e; + nrt_List *l = nrt_List_construct(&e); + TEST_ASSERT(l); + nrt_List_destruct(&l); + TEST_ASSERT_NULL(l); +} + +TEST_CASE(testPushPop) +{ + nrt_Error e; + nrt_List *l = NULL; + nrt_ListIterator it, endList; + int i = 0; + + l = nrt_List_construct(&e); + TEST_ASSERT(l); + + TEST_ASSERT(nrt_List_pushBack(l, (NRT_DATA *) "NITRO", &e)); + TEST_ASSERT(nrt_List_pushBack(l, (NRT_DATA *) "Rocks!", &e)); + + TEST_ASSERT_EQ_INT(2, nrt_List_size(l)); + + /* test iterating */ + it = nrt_List_begin(l); + endList = nrt_List_end(l); + for (; nrt_ListIterator_notEqualTo(&it, &endList); ++i) + { + char *p = (char *) nrt_ListIterator_get(&it); + TEST_ASSERT(p); + nrt_ListIterator_increment(&it); + } + TEST_ASSERT_EQ_INT(2, i); + + /* test emptying the list */ + it = nrt_List_begin(l); + while (!nrt_List_isEmpty(l)) + { + char *p = (char *) nrt_List_popFront(l); + TEST_ASSERT(p); + } + TEST_ASSERT_EQ_INT(0, nrt_List_size(l)); + nrt_List_destruct(&l); + TEST_ASSERT_NULL(l); +} + +char *cloneString(char *data, nrt_Error * error) +{ + int data_len = strlen(data); + char *new_data = (char *) NRT_MALLOC(data_len + 1); + new_data[data_len] = 0; + assert(new_data); + strcpy(new_data, data); + return new_data; +} + +TEST_CASE(testClone) +{ + nrt_Uint32 i; + nrt_Error e; + nrt_List *l = nrt_List_construct(&e), *dolly = NULL; + TEST_ASSERT(l); + + TEST_ASSERT(nrt_List_pushBack(l, (NRT_DATA *) cloneString("1", NULL), &e)); + TEST_ASSERT(nrt_List_pushBack(l, (NRT_DATA *) cloneString("2", NULL), &e)); + TEST_ASSERT(nrt_List_pushBack(l, (NRT_DATA *) cloneString("3", NULL), &e)); + TEST_ASSERT(nrt_List_pushBack(l, (NRT_DATA *) cloneString("4", NULL), &e)); + TEST_ASSERT(nrt_List_pushBack(l, (NRT_DATA *) cloneString("5", NULL), &e)); + + dolly = nrt_List_clone(l, (NRT_DATA_ITEM_CLONE) cloneString, &e); + TEST_ASSERT(dolly); + TEST_ASSERT_EQ_INT(nrt_List_size(l), nrt_List_size(dolly)); + + i = 0; + while (!nrt_List_isEmpty(dolly)) + { + char *p = (char *) nrt_List_popFront(dolly); + TEST_ASSERT(p); + TEST_ASSERT_EQ_INT(NRT_ATO32(p), ++i); + } + + TEST_ASSERT_EQ_INT(0, nrt_List_size(dolly)); + nrt_List_destruct(&dolly); + TEST_ASSERT_NULL(dolly); + nrt_List_destruct(&l); + TEST_ASSERT_NULL(l); +} + +TEST_CASE(testIterate) +{ + nrt_Uint32 i; + nrt_Error e; + nrt_List *l = nrt_List_construct(&e), *dolly = NULL; + nrt_ListIterator it, end; + + TEST_ASSERT(l); + + TEST_ASSERT(nrt_List_pushBack(l, (NRT_DATA *) cloneString("1", NULL), &e)); + TEST_ASSERT(nrt_List_pushBack(l, (NRT_DATA *) cloneString("2", NULL), &e)); + TEST_ASSERT(nrt_List_pushBack(l, (NRT_DATA *) cloneString("3", NULL), &e)); + TEST_ASSERT(nrt_List_pushBack(l, (NRT_DATA *) cloneString("4", NULL), &e)); + TEST_ASSERT(nrt_List_pushBack(l, (NRT_DATA *) cloneString("5", NULL), &e)); + + it = nrt_List_begin(l); + end = nrt_List_end(l); + + i = 0; + while (nrt_ListIterator_notEqualTo(&it, &end)) + { + char *p = (char *) nrt_ListIterator_get(&it); + TEST_ASSERT(p); + TEST_ASSERT_EQ_INT(NRT_ATO32(p), ++i); + nrt_ListIterator_increment(&it); + } + + nrt_List_destruct(&l); + TEST_ASSERT_NULL(l); +} + +TEST_CASE(testIterateRemove) +{ + nrt_Error e; + nrt_List *l = nrt_List_construct(&e), *dolly = NULL; + nrt_ListIterator it, end; + + TEST_ASSERT(l); + + TEST_ASSERT(nrt_List_pushBack(l, (NRT_DATA *) cloneString("1", NULL), &e)); + TEST_ASSERT(nrt_List_pushBack(l, (NRT_DATA *) cloneString("2", NULL), &e)); + TEST_ASSERT(nrt_List_pushBack(l, (NRT_DATA *) cloneString("3", NULL), &e)); + TEST_ASSERT(nrt_List_pushBack(l, (NRT_DATA *) cloneString("4", NULL), &e)); + TEST_ASSERT(nrt_List_pushBack(l, (NRT_DATA *) cloneString("5", NULL), &e)); + + it = nrt_List_begin(l); + end = nrt_List_end(l); + + while (nrt_ListIterator_notEqualTo(&it, &end)) + { + char *p = (char *) nrt_List_remove(l, &it); + TEST_ASSERT(p); + } + TEST_ASSERT_EQ_INT(0, nrt_List_size(l)); + + nrt_List_destruct(&l); + TEST_ASSERT_NULL(l); +} + +int main(int argc, char **argv) +{ + CHECK(testCreate); + CHECK(testPushPop); + CHECK(testClone); + CHECK(testIterate); + CHECK(testIterateRemove); + return 0; +} diff --git a/modules/c/nrt/unittests/test_nrt_datetime.c b/modules/c/nrt/unittests/test_nrt_datetime.c new file mode 100644 index 000000000..2bafe8ce2 --- /dev/null +++ b/modules/c/nrt/unittests/test_nrt_datetime.c @@ -0,0 +1,193 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, If not, + * see . + * + */ + +#include +#include "Test.h" + +#define MAX_DATE_STRING 1024 +#define NRT_DATE_FORMAT_21 "%Y%m%d%H%M%S" +#define NRT_FDT_SZ 14 + +NRTPRIV(void) printDate(nrt_DateTime * date) +{ + printf("Year: %d\n", date->year); + printf("Month: %d\n", date->month); + printf("Day Of Month: %d\n", date->dayOfMonth); + printf("Day Of Week: %d\n", date->dayOfWeek); + printf("Day Of Year: %d\n", date->dayOfYear); + printf("Hour: %d\n", date->hour); + printf("Minute: %d\n", date->minute); + printf("Second: %f\n", date->second); + printf("Millis: %f\n", date->timeInMillis); +} + +TEST_CASE(testNow) +{ + nrt_DateTime *date = NULL; + nrt_Error e; + + date = nrt_DateTime_now(&e); + TEST_ASSERT(date); + + nrt_DateTime_destruct(&date); + TEST_ASSERT_NULL(date); +} + +TEST_CASE(testFromMillis) +{ + nrt_DateTime *date = NULL, *date2 = NULL; + nrt_Error e; + + date = nrt_DateTime_now(&e); + TEST_ASSERT(date); + + date2 = nrt_DateTime_fromMillis(date->timeInMillis, &e); + TEST_ASSERT(date2); + + TEST_ASSERT((date->timeInMillis == date2->timeInMillis)); + + nrt_DateTime_destruct(&date); + nrt_DateTime_destruct(&date2); + TEST_ASSERT_NULL(date); + TEST_ASSERT_NULL(date2); +} + +TEST_CASE(testRoundTrip) +{ + nrt_DateTime *date = NULL, *date2 = NULL; + char buf[MAX_DATE_STRING], buf2[MAX_DATE_STRING]; + nrt_Error e; + + date = nrt_DateTime_now(&e); + TEST_ASSERT(date); + + /* printDate(date); */ + + TEST_ASSERT((nrt_DateTime_format + (date, NRT_DATE_FORMAT_21, buf, NRT_FDT_SZ + 1, &e))); + /* printf("Date: %s\n", buf); */ + + date2 = nrt_DateTime_fromString(buf, NRT_DATE_FORMAT_21, &e); + TEST_ASSERT(date2); + + TEST_ASSERT((nrt_DateTime_format + (date2, NRT_DATE_FORMAT_21, buf2, NRT_FDT_SZ + 1, &e))); + /* printf("Date: %s\n", buf2); */ + /* printDate(date2); */ + + TEST_ASSERT_EQ_STR(buf, buf2); + + /* must subtract off the millis - since our format string doesn't include + * them */ + nrt_DateTime_setSecond(date, (int) date->second, &e); + nrt_DateTime_setSecond(date2, (int) date2->second, &e); + TEST_ASSERT_EQ_FLOAT(date->timeInMillis, date2->timeInMillis); + + nrt_DateTime_destruct(&date); + nrt_DateTime_destruct(&date2); + TEST_ASSERT_NULL(date); + TEST_ASSERT_NULL(date2); +} + +TEST_CASE(testSetIdentity) +{ + nrt_DateTime *date = NULL; + char buf[MAX_DATE_STRING], buf2[MAX_DATE_STRING]; + nrt_Error e; + + date = nrt_DateTime_now(&e); + TEST_ASSERT(date); + + TEST_ASSERT((nrt_DateTime_format + (date, NRT_DATE_FORMAT_21, buf, NRT_FDT_SZ + 1, &e))); + + /* set hour */ + TEST_ASSERT(nrt_DateTime_setHour(date, date->hour, &e)); + TEST_ASSERT((nrt_DateTime_format + (date, NRT_DATE_FORMAT_21, buf2, NRT_FDT_SZ + 1, &e))); + TEST_ASSERT_EQ_STR(buf, buf2); + + /* set minute */ + TEST_ASSERT(nrt_DateTime_setMinute(date, date->minute, &e)); + TEST_ASSERT((nrt_DateTime_format + (date, NRT_DATE_FORMAT_21, buf2, NRT_FDT_SZ + 1, &e))); + TEST_ASSERT_EQ_STR(buf, buf2); + + /* set second */ + TEST_ASSERT(nrt_DateTime_setSecond(date, date->second, &e)); + TEST_ASSERT((nrt_DateTime_format + (date, NRT_DATE_FORMAT_21, buf2, NRT_FDT_SZ + 1, &e))); + TEST_ASSERT_EQ_STR(buf, buf2); + + /* set month */ + TEST_ASSERT(nrt_DateTime_setMonth(date, date->month, &e)); + TEST_ASSERT((nrt_DateTime_format + (date, NRT_DATE_FORMAT_21, buf2, NRT_FDT_SZ + 1, &e))); + TEST_ASSERT_EQ_STR(buf, buf2); + + /* set month */ + TEST_ASSERT(nrt_DateTime_setYear(date, date->year, &e)); + TEST_ASSERT((nrt_DateTime_format + (date, NRT_DATE_FORMAT_21, buf2, NRT_FDT_SZ + 1, &e))); + TEST_ASSERT_EQ_STR(buf, buf2); + + nrt_DateTime_destruct(&date); + TEST_ASSERT_NULL(date); +} + +TEST_CASE(testMillis) +{ + nrt_Error e; + char buf[MAX_DATE_STRING]; + const char *timeStr = "2010-01-12T22:55:37.123456Z"; + nrt_DateTime *date = NULL; + + date = nrt_DateTime_fromString(timeStr, "%Y-%m-%dT%H:%M:%SZ", &e); + TEST_ASSERT(date); + + TEST_ASSERT_EQ_INT((int) (1000 * (date->second - (int) date->second)), 123); + + nrt_DateTime_format(date, "%S", buf, MAX_DATE_STRING, &e); + TEST_ASSERT_EQ_STR(buf, "37"); + + nrt_DateTime_format(date, "%.3S", buf, MAX_DATE_STRING, &e); + TEST_ASSERT_EQ_STR(buf, "37.123"); + + nrt_DateTime_format(date, "%Y%.3S", buf, MAX_DATE_STRING, &e); + TEST_ASSERT_EQ_STR(buf, "201037.123"); + + nrt_DateTime_format(date, "%Y-%m-%dT%H:%M:%.6SZ", buf, MAX_DATE_STRING, &e); + TEST_ASSERT_EQ_STR(buf, timeStr); + + nrt_DateTime_destruct(&date); + TEST_ASSERT_NULL(date); +} + +int main(int argc, char **argv) +{ + CHECK(testNow); + CHECK(testFromMillis); + CHECK(testRoundTrip); + CHECK(testSetIdentity); + CHECK(testMillis); + return 0; +} diff --git a/modules/c/nrt/unittests/test_tree.c b/modules/c/nrt/unittests/test_tree.c new file mode 100644 index 000000000..810e38d58 --- /dev/null +++ b/modules/c/nrt/unittests/test_tree.c @@ -0,0 +1,122 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; + * If not, see . + * + */ + +#include +#include "Test.h" + +char *C(const char *p) +{ + char *x = malloc(strlen(p) + 1); + strcpy(x, p); + return x; +} + +NRT_BOOL deleteData(nrt_TreeNode * source, NRT_DATA * userData, int depth, + nrt_Error * error) +{ + char *p = (char *) source->data; + printf("Deleting %s\n", p); + free(p); + return 1; +} + +void makeTree(nrt_Tree * t, const char *testName) +{ + nrt_Error e; + nrt_TreeNode *an, *ancho, *abso; + t->root = nrt_TreeNode_construct(C("a"), &e); + TEST_ASSERT(t->root); + + an = nrt_TreeNode_construct(C("an"), &e); + TEST_ASSERT(an); + + nrt_TreeNode_addChild(t->root, an, &e); + + ancho = nrt_TreeNode_construct(C("ancho"), &e); + + nrt_TreeNode_addChild(an, ancho, &e); + + nrt_TreeNode_addChild(an, nrt_TreeNode_construct(C("anomaly"), &e), &e); + + nrt_TreeNode_addChild(ancho, nrt_TreeNode_construct(C("anchovy"), &e), &e); + nrt_TreeNode_addChild(ancho, nrt_TreeNode_construct(C("anchor"), &e), &e); + + abso = nrt_TreeNode_construct(C("absolut"), &e); + TEST_ASSERT(abso); + + nrt_TreeNode_addChild(t->root, abso, &e); + + nrt_TreeNode_addChild(abso, nrt_TreeNode_construct(C("absolute"), &e), &e); + nrt_TreeNode_addChild(abso, nrt_TreeNode_construct(C("absolution"), &e), + &e); + +} + +NRT_BOOL printElement(nrt_TreeNode * t, NRT_DATA * ud, int depth, nrt_Error * e) +{ + const char *p = (const char *) t->data; + int i; + + for (i = 0; i < depth; i++) + printf(" "); + printf("%s depth=\"%d\"\n", p, depth); + return 1; +} + +TEST_CASE(testTree) +{ + nrt_Error e; + + /* Create a tree - root can be passed during or after */ + nrt_Tree *t = nrt_Tree_construct(NULL, &e); + nrt_Tree *tc = NULL; + TEST_ASSERT(t); + + makeTree(t, testName); + printf("Pre-order traversal:\n"); + printf("=======================================================\n"); + TEST_ASSERT(nrt_Tree_walk(t, &printElement, NRT_PRE_ORDER, NULL, &e)); + + printf("\n\n"); + + tc = nrt_Tree_clone(t, (NRT_DATA_ITEM_CLONE) & C, &e); + TEST_ASSERT(tc); + + printf("Post-order traversal (cloned):\n"); + printf("=======================================================\n"); + TEST_ASSERT(nrt_Tree_walk(tc, &printElement, NRT_POST_ORDER, NULL, &e)); + + TEST_ASSERT(nrt_Tree_walk(t, &deleteData, NRT_POST_ORDER, NULL, &e)); + TEST_ASSERT(nrt_Tree_walk(tc, &deleteData, NRT_POST_ORDER, NULL, &e)); + + nrt_Tree_destruct(&t); + nrt_Tree_destruct(&tc); + + TEST_ASSERT_NULL(t); + TEST_ASSERT_NULL(tc); +} + +int main(int argc, char **argv) +{ + CHECK(testTree); + return 0; +} diff --git a/modules/c/nrt/wscript b/modules/c/nrt/wscript new file mode 100644 index 000000000..6a729c9b6 --- /dev/null +++ b/modules/c/nrt/wscript @@ -0,0 +1,27 @@ +import os +from waflib import Options + +NAME = 'nrt' +MAINTAINER = 'tzellman@users.sourceforge.net gojira_1@users.sourceforge.net' +VERSION = '2.7' +MODULE_DEPS = '' +LANG = 'c' +USELIB = 'THREAD DL RT MATH' +DEFINES = 'NRT_MODULE_EXPORTS' + + +configure = options = distclean = lambda p: None + +def build(bld): + env = bld.module(**globals()) + + + #run doxygen + if 'DOXYGEN' in env and Options.is_install: + bld(rule='${DOXYGEN}', cwd=bld.path.abspath(), always=True) + try: + htmlDocs = bld.path.find_dir('doc/html') + for f in htmlDocs.find_iter(): + relpath = f.path_from(htmlDocs) + bld.install_files('${PREFIX}/share/doc/nitf/c/%s' % relpath, f.abspath()) + except:{} diff --git a/modules/drivers/xml/expat/expat-1.95.7.tar b/modules/drivers/xml/expat/expat-1.95.7.tar new file mode 100644 index 000000000..e5b397b1e Binary files /dev/null and b/modules/drivers/xml/expat/expat-1.95.7.tar differ diff --git a/modules/drivers/xml/expat/expat-2.0.0.tar b/modules/drivers/xml/expat/expat-2.0.0.tar new file mode 100644 index 000000000..b044fe659 Binary files /dev/null and b/modules/drivers/xml/expat/expat-2.0.0.tar differ diff --git a/modules/drivers/xml/expat/wscript b/modules/drivers/xml/expat/wscript new file mode 100644 index 000000000..c76f45f59 --- /dev/null +++ b/modules/drivers/xml/expat/wscript @@ -0,0 +1,119 @@ +import os, sys +from os.path import join, exists +from waflib import Options +from waflib.TaskGen import feature, before, task_gen +from build import untarFile + +SOURCE = 'expat-2.0.0' +EXPAT_DEFINES = ['USE_EXPAT'] + +options = lambda x : None + +def configure(conf): + + xmlHome = Options.options.xml_home + xmlLayer = Options.options.xml_layer + + if xmlLayer == 'expat': + # add defines + # XML_STATIC depends on the --shared option + expatDefines = EXPAT_DEFINES + if not Options.options.shared_libs: + expatDefines.append('XML_STATIC') + conf.env.append_value('DEFINES_XML', expatDefines) + + # use an already built version + if xmlHome: + # attempt to test the third party library -- + # if test fails then fail the configure + conf.check(lib='expat', uselib_store='XML', + header_name='expat.h', + function_name='XML_ExpatVersion', + libpath=join(xmlHome, 'lib'), + includes=join(xmlHome, 'include'), + msg='Checking for library expat', okmsg=xmlHome, + mandatory=True) + + # build it with waf + elif Options.options.build_xml: + # check for the source tarball + if not exists(join(conf.path.abspath(), SOURCE + '.tar')): + conf.fatal('Missing expat tarfile') + + # untar and setup env + conf.env['MAKE_EXPAT'] = True + conf.env['MAKE_XML'] = True + conf.msg('Building local lib', xmlLayer) + untarFile(path=conf.path, fname=SOURCE + '.tar') + + # use an already built version that's on the system + else: + # if test fails then fail the configure + conf.check(lib='expat', uselib_store='XML', + header_name='expat.h', + function_name='XML_ExpatVersion', + msg='Checking for library expat', + mandatory=True) + + +def build(bld): + + env = bld.get_env() + sourceFiles = [] + + # check it again just in case + if 'MAKE_EXPAT' in env: + + expatNode = bld.path.make_node(SOURCE) + + expatDefs = ['PACKAGE_VERSION="2.0.0"', + 'XML_CONTEXT_BYTES=1024', + 'XML_DTD=1', + 'XML_NS=1', + 'PACKAGE_STRING="expat 2.0.0"'] + if not Options.options.shared_libs: + expatDefs.append('XML_STATIC=1') + + sources = 'lib/xmlparse.c lib/xmltok.c lib/xmlrole.c' + features = 'c c%s' % env['LIB_TYPE'] or 'stlib' + if env['install_headers'] or env['install_source']: + features += ' add_targets' + + expat = bld(features=features, source=sources, + includes='.', export_includes='lib', + target='expat', path=expatNode, + uselib='XML', name='XML', env=env.derive(), + defines=env['DEFINES'] + expatDefs) + expat.targets_to_add = [] + if env['install_libs']: + expat.install_path = env['install_libdir'] + + if env['CC_NAME'] == 'msvc' and env['LIB_TYPE'] == 'shlib': + expat.defs = 'lib/libexpat.def' + + if env['install_headers']: + bld(features='install_tgt', install_path=env['install_includedir'], + dir=expatNode, files=['lib/expat.h', 'lib/expat_external.h'], + name='XML_HEADERS_INSTALL') + expat.targets_to_add += ['XML_HEADERS_INSTALL'] + + if env['install_source']: + sourceNode = bld.path.make_node('source') + bld.install_tgt(files=SOURCE + '.tar', + dir=bld.path, + install_path=join('${PREFIX}', + sourceNode.path_from(bld.path)), + relative_trick=True, + name='XML_SOURCE_INSTALL') + expat.targets_to_add += ['XML_SOURCE_INSTALL'] + +def distclean(context): + + # remove the untarred directories + import shutil + dirs = filter(lambda x: exists(join(context.path.abspath(), x)), + ['expat-1.95.7','expat-2.0.0']) + for d in dirs: + try: + shutil.rmtree(join(context.path.abspath(), d), ignore_errors=True) + except:{} diff --git a/modules/drivers/xml/libxml/wscript b/modules/drivers/xml/libxml/wscript new file mode 100644 index 000000000..0a224aea2 --- /dev/null +++ b/modules/drivers/xml/libxml/wscript @@ -0,0 +1,37 @@ +import os, sys +from waflib import Options +from waflib.TaskGen import feature, before, task_gen +from build import untarFile + +LIBXML_DEFINES = 'USE_LIBXML' + +options = build = distclean = lambda x : None + +def configure(conf): + + xmlHome = Options.options.xml_home + xmlLayer = Options.options.xml_layer + + if xmlLayer == 'libxml' : + conf.env.append_value('DEFINES_XML', LIBXML_DEFINES.split()) + + # use an already built version + if xmlHome: + # attempt to test the third party library -- + # if test fails then fail the configure + conf.check(lib='xml2', uselib_store='XML', + header_name='libxml/parser.h', + function_name='xmlSAXVersion', + libpath=os.path.join(xmlHome, 'lib'), + includes=os.path.join(xmlHome, 'include'), + msg='Checking for library libxml', okmsg=xmlHome, + mandatory=True) + + # we don't currently support building within waf, + # so use an already built version that's on the system + else: + conf.check(lib='xml2', uselib_store='XML', + header_name='libxml/parser.h', + function_name='xmlSAXVersion', + msg='Checking for library libxml', + mandatory=True) diff --git a/modules/drivers/xml/wscript b/modules/drivers/xml/wscript new file mode 100644 index 000000000..c75354a8b --- /dev/null +++ b/modules/drivers/xml/wscript @@ -0,0 +1,39 @@ +import os, sys +from os.path import join, exists +from waflib import Options +from waflib.TaskGen import feature, before, task_gen +from build import untarFile + +APIS = 'expat libxml xerces' + +def options(opt): + opt.add_option('--disable-xml', action='store_false', dest='enable_xml', default=True, + help='turn off XML') + opt.add_option('--xml-layer', action='store', choices=APIS.split(), + dest='xml_layer', default='xerces', help='Specify the XML layer (default=xerces)') + opt.add_option('--with-xml-home', action='store', dest='xml_home', + help='Specify the XML Home - where the XML library is installed to') + opt.add_option('--build-xml', action='store_true', dest='build_xml', + help='force building XML layer from scratch', default=True) + opt.add_option('--nobuild-xml', action='store_false', dest='build_xml', + help='force not building XML layer from scratch') + + existingDirs = filter(lambda x: exists(join(opt.path.abspath(), x)), APIS.split()) + opt.recurse(existingDirs) + +def configure(conf): + if Options.options.enable_xml: + conf.msg('Configuring with XML layer', Options.options.xml_layer) + existingDirs = filter(lambda x: exists(join(conf.path.abspath(), x)), APIS.split()) + conf.recurse(existingDirs) + +def build(bld): + + existingDirs = filter(lambda x: exists(join(bld.path.abspath(), x)), APIS.split()) + bld.recurse(existingDirs) + +def distclean(context): + + existingDirs = filter(lambda x: exists(join(context.path.abspath(), x)), APIS.split()) + context.recurse(existingDirs) + diff --git a/modules/drivers/xml/xerces/wscript b/modules/drivers/xml/xerces/wscript new file mode 100644 index 000000000..b6c6c1dfd --- /dev/null +++ b/modules/drivers/xml/xerces/wscript @@ -0,0 +1,356 @@ +import os, sys +from os.path import join, exists +from waflib import Options +from waflib.TaskGen import feature, before, task_gen +from build import untarFile + +SOURCE = 'xerces-c-3.1.1' +XERCES_DEFINES = ['USE_XERCES'] +XERCES_USELIBS = 'XML THREAD SOCKET' + +options = lambda x : None + +def configure(conf): + + xmlHome = Options.options.xml_home + xmlLayer = Options.options.xml_layer + + if xmlLayer == 'xerces' : + + # add defines -- + # XERCESC_STATIC_LIBRARY depends on the --shared option + xercesDefines = XERCES_DEFINES + if not Options.options.shared_libs: + xercesDefines.append('XERCES_STATIC_LIBRARY') + conf.env.append_value('DEFINES_XML', xercesDefines) + + xercesUselibs = XERCES_USELIBS + if sys.platform == 'win32': + # Xerces requires this standard Windows library + conf.check_cc(lib='advapi32', uselib_store='ADVAPI32') + xercesUselibs += ' ADVAPI32' + + # use an already built version + if xmlHome: + # attempt to test the third party library -- + # if test fails then fail the configure + conf.check(lib='xerces-c', uselib_store='XML', + header_name='xercesc/util/PlatformUtils.hpp', + function_name='xercesc::XMLPlatformUtils::Terminate', + defines='XERCES_STATIC_LIBRARY', uselib=xercesUselibs, + libpath=join(xmlHome, 'lib'), + includes=join(xmlHome, 'include'), + msg='Checking for library xerces', okmsg=xmlHome, + mandatory=True) + + # build it with waf + elif Options.options.build_xml: + # check for the source tarball + if not exists(join(conf.path.abspath(), SOURCE + '.tar')): + conf.fatal('Missing xerces tarfile') + + conf.check_cc(header_name="netinet/in.h", mandatory=False) + conf.check_cc(header_name="arpa/inet.h", mandatory=False) + conf.check_cc(header_name="netdb.h", mandatory=False) + conf.check_cc(header_name="intrin.h", mandatory=False) + conf.check_cc(header_name="emmintrin.h", mandatory=False) + conf.check_cc(header_name="wchar.h", mandatory=False) + conf.check_cc(header_name="stdint.h", mandatory=False) + conf.check_cc(header_name="stdio.h", mandatory=False) + conf.check_cc(header_name="langinfo.h", mandatory=False) + conf.check_cc(header_name="iconv.h", mandatory=False) + conf.check_cc(header_name="nl_types.h", mandatory=False) + conf.check_cc(header_name="ctype.h", mandatory=False) + conf.check_cc(header_name="wctype.h", mandatory=False) + conf.check_cc(header_name="cpuid.h", mandatory=False) + conf.check_cc(header_name="endian.h", mandatory=False) + conf.check_cc(header_name="machine/endian.h", mandatory=False) + conf.check_cc(header_name="arpa/nameser_compat.h", mandatory=False) + conf.check_cc(header_name="errno.h", mandatory=False) + conf.check_cc(header_name="float.h", mandatory=False) + conf.check_cc(header_name="locale.h", mandatory=False) + conf.check_cc(header_name="sys/param.h", mandatory=False) + conf.check_cc(header_name="sys/socket.h", mandatory=False) + conf.check_cc(header_name="sys/stat.h", mandatory=False) + conf.check_cc(header_name="sys/timeb.h", mandatory=False) + conf.check_cc(header_name="sys/types.h", mandatory=False) + + conf.check_cc(function_name='mblen', header_name="stdlib.h", mandatory=False) + conf.check_cc(function_name='mbrlen', header_name="stdlib.h", mandatory=False) + conf.check_cc(function_name='mbsrtowcs', header_name="stdlib.h", mandatory=False) + conf.check_cc(function_name='mbstowcs', header_name="stdlib.h", mandatory=False) + conf.check_cc(function_name='wsctombs', header_name="stdlib.h", mandatory=False) + conf.check_cc(function_name='wcsrtombs', header_name="stdlib.h", mandatory=False) + conf.check_cc(function_name='realpath', header_name="stdlib.h", mandatory=False) + conf.check_cc(function_name='strchr', header_name="string.h", mandatory=False) + conf.check_cc(function_name='strdup', header_name="string.h", mandatory=False) + conf.check_cc(function_name='stricmp', header_name="string.h", mandatory=False) + conf.check_cc(function_name='strnicmp', header_name="string.h", mandatory=False) + conf.check_cc(function_name='strrcmp', header_name="string.h", mandatory=False) + conf.check_cc(function_name='strstr', header_name="string.h", mandatory=False) + conf.check_cc(function_name='strtol', header_name="string.h", mandatory=False) + conf.check_cc(function_name='strtoul', header_name="string.h", mandatory=False) + conf.check_cc(function_name='strcasecmp', header_name="strings.h", mandatory=False) + conf.check_cc(function_name='strncasecmp', header_name="strings.h", mandatory=False) + conf.check_cc(function_name='pathconf', header_name="unistd.h", mandatory=False) + conf.check_cc(function_name='nl_langinfo', header_name="langinfo.h", mandatory=False) + conf.check_cc(function_name='iconv', header_name="iconv.h", mandatory=False) + conf.check_cc(function_name='iconv_close', header_name="iconv.h", mandatory=False) + conf.check_cc(function_name='iconv_open', header_name="iconv.h", mandatory=False) + conf.check_cc(function_name='towupper', header_name="wctype.h", mandatory=False) + conf.check_cc(function_name='towlower', header_name="wctype.h", mandatory=False) + conf.check_cc(function_name='catclose', header_name="nl_types.h", mandatory=False) + conf.check_cc(function_name='catclose', header_name="nl_types.h", mandatory=False) + conf.check_cc(function_name='catgets', header_name="nl_types.h", mandatory=False) + conf.check_cc(function_name='catopen', header_name="nl_types.h", mandatory=False) + conf.check_cc(function_name='localeconv', header_name="locale.h", mandatory=False) + conf.check_cc(function_name='setlocale', header_name="locale.h", mandatory=False) + conf.check_cc(function_name='socket', header_name="sys/socket.h", mandatory=False) + conf.check_cc(function_name='ftime', header_name="sys/timeb.h", mandatory=False) + conf.check_cc(function_name='getaddrinfo', header_name="netdb.h", mandatory=False) + + conf.check_cc(lib="nsl", mandatory=False, uselib_store='NSL') + + # untar and setup env + conf.env['MAKE_XERCES'] = True + conf.env['MAKE_XML'] = True + conf.msg('Building local lib', xmlLayer) + untarFile(path=conf.path, fname=SOURCE + '.tar') + + # use an already built version that's on the system + else : + # if test fails then fail the configure + conf.check(lib='xerces-c', uselib_store='XML', + header_name='xercesc/util/PlatformUtils.hpp', + function_name='xercesc::XMLPlatformUtils::Terminate', + defines='XERCES_STATIC_LIBRARY', uselib=xercesUselibs, + msg='Checking for library xerces', + mandatory=True) + + +def build(bld): + + env = bld.get_env() + sourceFiles = [] + + # check it again just in case + if 'MAKE_XERCES' in env: + + xercesNode = bld.path.make_node(SOURCE) + xercesUselibs = XERCES_USELIBS + if sys.platform == 'win32': + # Xerces requires this standard Windows library + xercesUselibs += ' ADVAPI32' + + d = {} + for line in env['DEFINES']: + split = line.split('=') + k = split[0] + v = len(split) == 2 and split[1] or '1' + if v: + d[k] = v + + # extra defines for config.h + if 'HAVE_ICONV_H=1' in env['DEFINES'] : + d['ICONV_USES_CONST_POINTER'] = '0' + if 'HAVE_SYS_TIME_H=1' in env['DEFINES'] and 'HAVE_TIME_H=1' in env['DEFINES']: + d['TIME_WITH_SYS_TIME'] = '1' + if 'HAVE_SYS_TYPES_H=1' in env['DEFINES'] : + d['XERCES_HAVE_SYS_TYPES_H'] = '1' + if 'HAVE_INTTYPES_H=1' in env['DEFINES'] : + d['XERCES_HAVE_INTTYPES_H'] = '1' + if 'HAVE_INTRIN_H=1' in env['DEFINES'] : + d['XERCES_HAVE_INTRIN_H'] = '1' + if 'HAVE_EMMINTRIN_H=1' in env['DEFINES'] : + d['XERCES_HAVE_EMMINTRIN_H'] = '1' + if 'HAVE_WCHAR_H=1' in env['DEFINES'] : + d['XERCES_INCLUDE_WCHAR_H'] = '1' + if 'HAVE_EMMINTRIN_H=1' in env['DEFINES'] : + d['XERCES_HAVE_SSE2_INTRINSIC'] = '1' + if sys.platform == 'win32' : + d['XERCES_USE_FILEMGR_WINDOWS'] = '1' + d['XERCES_USE_MUTEXMGR_WINDOWS'] = '1' + d['XERCES_USE_NETACCESSOR_WINSOCK'] = '1' + d['XERCES_USE_TRANSCODER_WINDOWS'] = '1' + d['XERCES_PATH_DELIMITER_BACKSLASH'] = '1' + + d['XERCES_S16BIT_INT'] = '__int16' + d['XERCES_S32BIT_INT'] = '__int32' + d['XERCES_S64BIT_INT'] = '__int32' + d['XERCES_U16BIT_INT'] = 'unsigned __int16' + d['XERCES_U32BIT_INT'] = 'unsigned __int32' + d['XERCES_U64BIT_INT'] = 'unsigned __int64' + d['XERCES_SIZE_T'] = 'size_t' + if 'HAVE_WCHAR_H=1' in env['DEFINES'] : + d['XERCES_XMLCH_T'] = 'wchar_t' + else : + d['XERCES_XMLCH_T'] = 'unsigned __int16' + if 'HAVE_SSIZE_T=1' in env['DEFINES'] : + d['XERCES_SSIZE_T'] = 'ssize_t' + else : + if 'SIZEOF_SIZE_T=8' in env['DEFINES'] : + d['XERCES_SSIZE_T'] = '__int64' + else : + d['XERCES_SSIZE_T'] = '__int32' + + # -- please note -- we diverge from the xerces-c make + # system and treat all unix platforms similarly. Solaris + # was make configured to use ICU and Linux the GNUICONV, + # but here we use the regular ICONV for both to avoid + # having complicated checks and additional build logic. + else : + d['HAVE_PTHREAD'] = '1' + + d['XERCES_USE_FILEMGR_POSIX'] = '1' + d['XERCES_USE_MUTEXMGR_POSIX'] = '1' + d['XERCES_USE_TRANSCODER_ICONV'] = '1' + + d['XERCES_S16BIT_INT'] = 'int16_t' + d['XERCES_S32BIT_INT'] = 'int32_t' + d['XERCES_S64BIT_INT'] = 'int64_t' + d['XERCES_U16BIT_INT'] = 'uint16_t' + d['XERCES_U32BIT_INT'] = 'uint32_t' + d['XERCES_U64BIT_INT'] = 'uint64_t' + d['XERCES_XMLCH_T'] = 'uint16_t' + d['XERCES_SIZE_T'] = 'size_t' + d['XERCES_SSIZE_T'] = 'ssize_t' + + d['LT_OBJDIR'] = '.libs/' + d['PACKAGE'] = 'xerces-c' + d['PACKAGE_BUGREPORT'] = '' + d['PACKAGE_NAME'] = 'xerces-c' + d['PACKAGE_STRING'] = 'xerces-c 3.1.1' + d['PACKAGE_TARNAME'] = 'xerces-c' + d['PACKAGE_URL'] = '' + d['PACKAGE_VERSION'] = '3.1.1' + d['VERSION'] = '3.1.1' + + # extra defines for Xerces_autoconf_config.hpp + d['XERCES_USE_MSGLOADER_INMEMORY'] = '1' + d['XERCES_BUILDING_LIBRARY'] = '1' + d['HAVE_NAMESPACES'] = '1' + d['HAVE_SOCKET'] = '1' + d['HAVE_STD_LIBS'] = '1' + d['HAVE_STD_NAMESPACE'] = '1' + + d['XERCES_AUTOCONF'] = '1' + d['XERCES_PLATFORM_EXPORT'] = '' + d['XERCES_PLATFORM_IMPORT'] = '' + d['XERCES_HAS_CPP_NAMESPACE'] = '1' + d['XERCES_STD_NAMESPACE'] = '1' + d['XERCES_NEW_IOSTREAMS'] = '1' + d['XERCES_LSTRSUPPORT'] = '1' + d['HAVE_BOOL'] = '1' + + if 'HAVE_NL_TYPES_H=1' in env['DEFINES'] : + d['HAVE_CATCLOSE'] = '1' + d['HAVE_CATGETS'] = '1' + d['HAVE_CATOPEN'] = '1' + + # first setup the configurable headers + xercesAutoH = bld(name='xercesAutoH', + features='handleDefs', + input='src/xercesc/util/Xerces_autoconf_config.hpp.in', + output='src/xercesc/util/Xerces_autoconf_config.hpp', + defs=d, path=xercesNode, + env=env.derive()) + xercesConfigH = bld(name='xercesConfigH', + features='handleDefs', + input='config.h.in', + output='config.h', + defs=d, path=xercesNode, + env=env.derive()) + + # setup some known excludes per platform -- + # we avoid building the system specific files + # and instead build the safely cross-platform files for all unix + # platforms. -- for more information see note above -- + GENERAL_EXCLUDES = ['URLAccessCFBinInputStream.cpp', + 'MacOSURLAccessCF.cpp', 'IconvGNUTransService.cpp', + 'MacOSUnicodeConverter.cpp', 'MsgCatalogLoader.cpp', + 'CurlURLInputStream.cpp', 'CurlNetAccessor.cpp', + 'ICUMsgLoader.cpp', 'ICUTransService.cpp', + 'Win32MsgLoader.cpp'] + UNIX_SPECIFIC = ['SocketNetAccessor.cpp','UnixHTTPURLInputStream.cpp', + 'PosixFileMgr.cpp', 'PosixMutexMgr.cpp', + 'IconvTransService.cpp'] + WIN_SPECIFIC = ['Win32TransService.cpp', 'WinSockNetAccessor.cpp', + 'BinHTTPURLInputStream.cpp', + 'BinHTTPInputStreamCommon.cpp', + 'WindowsFileMgr.cpp', 'WindowsMutexMgr.cpp'] + + # create filter for system specific files + # MacOS could be supported here as well + EXCLUDES = GENERAL_EXCLUDES + if sys.platform == 'win32' : + EXCLUDES += UNIX_SPECIFIC + else : + EXCLUDES += WIN_SPECIFIC + + # walk the directory of files -- + # this sorts files based on the filtering above, and + # whether they are sources vs headers + sources = [] + headers = [] + xercesDir = join(bld.path.abspath(), SOURCE) + for root,dirs,files in os.walk(join(xercesDir, 'src')) : + relativePath = root.replace(xercesDir + os.sep, "") + for file in files : + if file.endswith('.cpp') and 'Test' not in file and file not in EXCLUDES or \ + sys.platform != 'win32' and dirs == ['xercesc'] and file.endswith('.c') : + sources.append(join(relativePath, file)) + elif file.endswith('.h') or file.endswith('.hpp') or file.endswith('.c') : + headers.append(join(relativePath, file)) + sources = ' '.join(sources) + + # build the library + xercesDefines = env['DEFINES'] + ['HAVE_CONFIG_H'] + xerces = bld(features='c c%s add_targets' % env['LIB_TYPE'] or 'stlib', + source=sources, + includes=['.', 'src'], export_includes='src', + target='xerces-c', path=xercesNode, + uselib=xercesUselibs, name='XML', env=env.derive(), + defines=xercesDefines, + targets_to_add=[xercesAutoH, xercesConfigH]) + if env['install_libs']: + xerces.install_path = env['install_libdir'] + + if env['CC_NAME'] == 'msvc' and env['LIB_TYPE'] == 'shlib': + xerces.defs = 'lib/libxerces.def' + + # install header target if necessary + if env['install_headers']: + # install all hpp, h, and c files into the include directory in a relative structure + srcNode = xercesNode.make_node('src') + + # add the config.h file to the install + bld(features='install_tgt', pattern='*.h', + dir=xercesNode, install_path=env['install_includedir'], + name='XML_INCLUDE_CONFIG_H_INSTALL') + xerces.targets_to_add.append(bld(features='install_tgt add_targets', + pattern='**/*.hpp **/*.h xercesc/**/*.c', + dir=srcNode, install_path=env['install_includedir'], + name='XML_INCLUDE_INSTALL', + targets_to_add=['XML_INCLUDE_CONFIG_H_INSTALL'])) + + # install source target if necessary + if env['install_source']: + sourceNode = bld.path.make_node('source') + xerces.targets_to_add.append(bld.install_tgt(files=SOURCE + '.tar', + dir=bld.path, + install_path=join('${PREFIX}', + sourceNode.path_from(bld.path)), + relative_trick=True, + name='XML_SOURCE_INSTALL')) + +def distclean(context): + + # remove the untarred directories + import shutil + dirs = filter(lambda x: exists(join(context.path.abspath(), x)), + ['xerces-c-3.1.1']) + for d in dirs: + try: + shutil.rmtree(join(context.path.abspath(), d), ignore_errors=True) + except:{} + diff --git a/modules/drivers/xml/xerces/xerces-c-3.1.1.tar b/modules/drivers/xml/xerces/xerces-c-3.1.1.tar new file mode 100644 index 000000000..a953f7aa4 Binary files /dev/null and b/modules/drivers/xml/xerces/xerces-c-3.1.1.tar differ diff --git a/modules/mex/README.txt b/modules/mex/README.txt new file mode 100644 index 000000000..3b6a73559 --- /dev/null +++ b/modules/mex/README.txt @@ -0,0 +1,143 @@ +MATLAB INTERFACE + +Since 2007, matlab ships with its own nitf reader. The reader is +adequate for some purposes, but not all. The intent here is to externalize +all major nitf capabilities for read using NITRO's C core underneath + +The intent is to optionally support TRE extensions +(using the same TRE handlers that the C uses), as well as to support +compressed image reading (via any available NITRO decompression plugins) + +Disclaimer: This interface to matlab is under development and has not been +heavily tested yet. Testing has been done on v2007a/v2007b, and v2008b. + +You may have to tweak the configuration to get this working on +your system. Use at your own risk. + + +nitf_metadata +=========================================== +Function to read all the headers in a NITF: + +Example usage: + +If you do not set your NITF_PLUGIN_PATH and you do not pass the path as the +second argument, your output should look as follows: + +>> r = nitf_metadata(nitf) + +r = + + header: [1x1 struct] + images: {[1x1 struct]} +>> r.header + +ans = + + FHDR: 'NITF' + FVER: '02.10' + CLEVEL: '03' + STYPE: 'BF01' + OSTAID: 'I_3005A ' + FDT: '19970924152010' + FTITLE: 'Checks a JPEG-compressed 64x64 8-bit mono image, lincoln's face. W/image cmts. ' + FSCLAS: 'U' + FSCOP: '00001' + FSCPYS: '00001' + ENCRYP: '0' + ONAME: 'JITC Fort Huachuca, AZ ' + OPHONE: '(520) 538-5458 ' + FL: '000000002407' + HL: '000618' + NUMI: '001' + NUMS: '000' + NUMX: '000' + NUMT: '000' + NUMDES: '000' + NUMRES: '000' + UDHDL: '00000' + UDHOFL: '000' + XHDL: '00214' + XHDLOFL: '000' + FS: [1x1 struct] + UDHD: {0x1 cell} + XHD: {[1x1 struct]} + +>> r.header.XHD{1} + +ans = + + CETAG: 'JITCID' + raw_data: [1x200 char] + __treID__: 'raw_data' + +If you add the optional second argument, the last command will yield: + +>> npp = '/xdata1/u/dpressel/nitro/trunk/c/nitf/plugins/sparc-sun-solaris2.10-64'; +>> r = nitf_metadata(nitf, npp); +>> r.header.XHD{1} + +ans = + + CETAG: 'JITCID' + FILCMT: [1x200 char] + __treID__: 'JITCID' + +Notice that the TRE has one field 'FILMCT and NITRO parsed it this time. +__treID__ is not actually a part of the NITF TRE, it identifies what handler +NITRO used to parse the TRE. This sometimes matters if a TRE has more than one +description handler (some TREs evolve over time). NITRO tries to pick the +best handler and apply that, but sometimes its nice to know what it is + +>> r.images{1} + +ans = + + IM: 'IM' + IID1: 'Cmp_tst_01' + IDATIM: '19970924151512' + TGTID: ' ' + IID2: 'This is an unclassified image in an unclassified NITF file Q1. ' + ISCLAS: 'U' + ENCRYP: '0' + ISORCE: ' ' + NROWS: '00000064' + NCOLS: '00000064' + PVTYPE: 'INT' + IREP: 'MONO ' + ICAT: 'VIS ' + ABPP: '08' + PJUST: 'R' + ICORDS: ' ' + IGEOLO: ' ' + NICOM: '9' + ICOM: {9x1 cell} + IC: 'C3' + COMRAT: '00.0' + NBANDS: '1' + XBANDS: '00000' + bands: {[1x1 struct]} + ISYNC: '0' + IMODE: 'B' + NBPR: '0001' + NBPC: '0001' + NPPBH: '0064' + NPPBV: '0064' + NBPP: '08' + IDLVL: '001' + IALVL: '000' + ILOC: '0000000000' + IMAG: '1.0 ' + UDIDL: '00000' + UDOFL: '000' + IXSHDL: '00000' + IXSOFL: '000' + IS: [1x1 struct] + UDID: {0x1 cell} + XSHD: {0x1 cell} + + + +>> i_3301 = strcat(path2, '\i_3301a.ntf'); +>> out = nitf_image(i_3301, 'Window', [1, 1, 512, 512]); +>> imshow(out) \ No newline at end of file diff --git a/modules/mex/nitf_image-64.def b/modules/mex/nitf_image-64.def new file mode 100644 index 000000000..02573b35d --- /dev/null +++ b/modules/mex/nitf_image-64.def @@ -0,0 +1,2 @@ +LIBRARY nitf_image.mexw64 +EXPORTS mexFunction \ No newline at end of file diff --git a/modules/mex/nitf_image.c b/modules/mex/nitf_image.c new file mode 100644 index 000000000..266cb9490 --- /dev/null +++ b/modules/mex/nitf_image.c @@ -0,0 +1,969 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2008, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ +#include +#include "mex.h" + +/* + * Error handling method + * + */ +#define MEX_NTF_ERR(E) \ + mexErrMsgTxt(( (E)->level == NITF_ERR_UNK) ? ("Unknown Error") : ( (E)->message)) + + +/* + * Allocate a C-string from a Matlab array (returns NULL on error) + */ +static char* newString(const mxArray* mx) +{ + size_t len; + char* str; + + if (!mxIsChar(mx)) + return(NULL); + + if (mxGetM(mx) != 1) + return(NULL); + + len = (mxGetM(mx) * mxGetN(mx)) + 1; + str = (char*)malloc(len + 1); + str[len] = 0; + if (mxGetString(mx, str, len) != 0) + { + free(str); + return(NULL); + } + return str; +} + +/* + * Transpose a matrix + * + * The return is the transposed result, or NULL on error + * + * This either transposes the input in-place or allocates a new matrix and + * frees the input + */ + +mxArray *transpose(mxArray *org) +{ + return NULL; + + +} + + +/* + * Currently we will not handle merging images, but interface + * is set up to support in the future. If they wanted to + * merge pixel arrays, we could allow a magic -1 for segment + * ID + * + * All of these methods will attempt to use optimized mode if they + * have the opportunity. + * + * Everything is assumed to be validated prior to this call, and + * sizes/bands, etc, should be valid + */ + +typedef mxArray* (*MEX_NTF_IMREAD)(nitf_Reader* reader, + int idx, + long startRow, + long startCol, + long numRows, + long numCols, + nitf_Error *error); + + +nitf_SubWindow* createSubWindow(long startRow, + long startCol, + long numRows, + long numCols, + int numBands) +{ + /* Window size */ + nitf_SubWindow* subWindow; + + /* Band ordering list */ + nitf_Uint32* bandList = NULL; + + /* Starting bandID is always 1 for now */ + nitf_Uint32 bandID = 0; + + /* Error handler */ + nitf_Error error; + + /* Create the sub-window */ + subWindow = nitf_SubWindow_construct(&error); + + if (!subWindow) + return(NULL); + + /* + * This tells us what order to give you bands in. Normally + * you just want it in the order of the banding. For example, + * in a non-accelerated band-interleaved by pixel cases, you might + * have a band of magnitude and a band of phase. If you order the + * bandList backwards, the phase buffer comes first in the output + */ + bandList = (nitf_Uint32 *) malloc(sizeof(nitf_Uint32 *) * numBands); + if(bandList == NULL) + { + nitf_SubWindow_destruct(&subWindow); + return(NULL); + } + + for (bandID = 0; bandID < (nitf_Uint32)numBands; ++bandID) + bandList[bandID] = bandID; + + subWindow->numBands = numBands; + subWindow->startRow = startRow; + subWindow->startCol = startCol; + subWindow->numRows = numRows; + subWindow->numCols = numCols; + subWindow->bandList = bandList; + + return subWindow; +} + +mxArray* read32BitFloatPixelArray(nitf_Reader* reader, + int idx, + long startRow, + long startCol, + long numRows, + long numCols, + nitf_Error *error) +{ + int padded = 0; + + mxArray* mxImageArray = NULL; + + /* Window size */ + nitf_SubWindow* subWindow = NULL; + + /* Image Reader */ + nitf_ImageReader* imageReader = NULL; + + /* Buffer array ptr */ + nitf_Uint8* buffers[1]; + + nitf_Uint8* buffer = NULL; + + int numBands = 1; + + /* Do this first to avoid abort on fail causing memory leak */ + + mxImageArray = + mxCreateNumericMatrix(numCols, numRows, mxSINGLE_CLASS, mxREAL); + + /* Create the sub-window - will fail internally if error */ + subWindow = createSubWindow(startRow, startCol, + numRows, numCols, numBands); + + /* Now attach the buffer up to the mxImageArray */ + buffer = (nitf_Uint8*)mxGetData(mxImageArray); + + /* Only works with one band */ + buffers[0] = buffer; + + /* Image reader (could fail) */ + imageReader = nitf_Reader_newImageReader(reader, idx, NULL, error); + if (imageReader == NULL) + goto CATCH_ERROR; + + /* Now read the data */ + if(!nitf_ImageReader_read(imageReader, subWindow, buffers, &padded, error)) + goto CATCH_ERROR; + + if(subWindow != NULL) + nitf_SubWindow_destruct(&subWindow); + if(imageReader != NULL) + nitf_ImageReader_destruct(&imageReader); + + return mxImageArray; + +CATCH_ERROR: + + if(subWindow != NULL) + nitf_SubWindow_destruct(&subWindow); + if(imageReader != NULL) + nitf_ImageReader_destruct(&imageReader); + if(mxImageArray != NULL); + mxFree(mxImageArray); + return NULL; +} + +/* + * This case is totally straightforwad. We just read in the + * pixel array and create a matrix value. + * + * Things in the matlab world are one-based but these functions + * assume that the arguments here are 0-based + */ +mxArray* readSingleBandPixelArray(nitf_Reader* reader, + int idx, + int matlabClassType, + long startRow, + long startCol, + long numRows, + long numCols, + nitf_Error *error) +{ + + int padded = 0; + + mxArray* mxImageArray = NULL; + + /* Window size */ + nitf_SubWindow* subWindow = NULL; + + /* Image Reader */ + nitf_ImageReader* imageReader = NULL; + + /* Buffer array ptr */ + nitf_Uint8** buffers = NULL; + + nitf_Uint8* buffer = NULL; + + int numBands = 1; + + /* Create the sub-window - will fail internally if error */ + subWindow = createSubWindow(startRow, startCol, + numRows, numCols, numBands); + + /* Create the image buffer - will fail internally if error */ + buffers = (nitf_Uint8**)malloc( sizeof(nitf_Uint8*) * numBands); + + mxImageArray = + mxCreateNumericMatrix(numCols, numRows, matlabClassType, mxREAL); + + /* Now attach the buffer up to the mxImageArray */ + buffer = (nitf_Uint8*)mxGetData(mxImageArray); + + /* Only works with one band */ + buffers[0] = buffer; + + /* Image reader (could fail) */ + imageReader = nitf_Reader_newImageReader(reader, idx, NULL, error); + if (!imageReader) + goto CATCH_ERROR; + + /* Now read the data */ + if (!nitf_ImageReader_read(imageReader, subWindow, + buffers, &padded, error)) + goto CATCH_ERROR; + + if(subWindow != NULL) + nitf_SubWindow_destruct(&subWindow); + if(imageReader != NULL) + nitf_ImageReader_destruct(&imageReader); + + return mxImageArray; + +CATCH_ERROR: + + if(subWindow != NULL) + nitf_SubWindow_destruct(&subWindow); + if(imageReader != NULL) + nitf_ImageReader_destruct(&imageReader); + if(mxImageArray != NULL); + mxFree(mxImageArray); + return NULL; +} + +/* + * This case is totally straightforwad. We just read in the + * pixel array and create a matrix value. + * + * Things in the matlab world are one-based but these functions + * assume that the arguments here are 0-based + */ +mxArray* read16BitPixelArray(nitf_Reader* reader, + int idx, + long startRow, + long startCol, + long numRows, + long numCols, + nitf_Error *error) +{ + + return readSingleBandPixelArray(reader, idx, mxUINT16_CLASS, startRow, startCol, numRows, numCols, error); +} + +/* + * This case is totally straightforwad. We just read in the + * pixel array and create a matrix value. + * + * Things in the matlab world are one-based but these functions + * assume that the arguments here are 0-based + */ +mxArray* read8BitPixelArray(nitf_Reader* reader, + int idx, + long startRow, + long startCol, + long numRows, + long numCols, + nitf_Error *error) +{ + + return readSingleBandPixelArray(reader, idx, mxUINT8_CLASS, startRow, startCol, numRows, numCols, error); +} + +/* + * Two band Complex pixel, the I/Q or M/P case + * + * This case is mostly straightforwad. We just read in the pixel + * array and create a matrix value. Need to assign Pr and Pi to + * the correct band I/Q or M/P can be in any order, but for this version, + * we will assume that they will be ordered, I then Q. + * + * + * Things in the matlab world are one-based but these functions + * assume that the arguments here are 0-based + */ +mxArray* read2BandComplexPixelArray(nitf_Reader* reader, + int idx, + int matlabClassType, + long startRow, + long startCol, + long numRows, + long numCols, + nitf_Error *error) +{ + + int padded = 0; + + mxArray* mxImageArray = NULL; + + /* Window size */ + nitf_SubWindow* subWindow = NULL; + + /* Image Reader */ + nitf_ImageReader* imageReader = NULL; + + /* Buffer array ptr */ + nitf_Uint8* buffers[2]; + + int numBands = 2; + +/* + * Do this here since if it failes the whole function aborts and there is + * no chance to clean-up + */ + mxImageArray = + mxCreateNumericMatrix(numCols, numRows, matlabClassType, mxCOMPLEX); + + /* Create the sub-window - will fail internally if error */ + subWindow = createSubWindow(startRow, startCol, + numRows, numCols, numBands); + + + /* Now attach the buffer up to the mxImageArray */ + buffers[0] = (nitf_Uint8*)mxGetData(mxImageArray); + buffers[1] = (nitf_Uint8*)mxGetImagData(mxImageArray); + + /* Image reader (could fail) */ + imageReader = nitf_Reader_newImageReader(reader, idx, NULL, error); + if (!imageReader) + goto CATCH_ERROR; + + /* Now read the data */ + if (!nitf_ImageReader_read(imageReader, subWindow, + buffers, &padded, error)) + goto CATCH_ERROR; + + if(subWindow != NULL) + nitf_SubWindow_destruct(&subWindow); + if(imageReader != NULL) + nitf_ImageReader_destruct(&imageReader); + + return mxImageArray; + +CATCH_ERROR: + + if(subWindow != NULL) + nitf_SubWindow_destruct(&subWindow); + if(imageReader != NULL) + nitf_ImageReader_destruct(&imageReader); + if(mxImageArray != NULL); + mxFree(mxImageArray); + return NULL; +} + +mxArray* readIQComplexFloatPixelArray(nitf_Reader* reader, + int idx, + long startRow, + long startCol, + long numRows, + long numCols, + nitf_Error *error) +{ + + return(read2BandComplexPixelArray(reader, + idx, + mxSINGLE_CLASS, + startRow, + startCol, + numRows, + numCols, + error)); +} + +mxArray* readIQSignedIntPixelArray(nitf_Reader* reader, + int idx, + long startRow, + long startCol, + long numRows, + long numCols, + nitf_Error *error) +{ + + return(read2BandComplexPixelArray(reader, + idx, + mxINT16_CLASS, + startRow, + startCol, + numRows, + numCols, + error)); +} + + +mxArray* read24BitPixelArray(nitf_Reader* reader, + int idx, + long startRow, + long startCol, + long numRows, + long numCols, + nitf_Error *error) +{ + int padded = 0; + + mxArray* mxImageArray = NULL; + /* Window size */ + nitf_SubWindow* subWindow = NULL; + + /* Image Reader */ + nitf_ImageReader* imageReader = NULL; + + /* Buffer array ptr */ + nitf_Uint8* buffers[2]; + + const mwSize dims[] = { numCols, numRows, 3 }; + const int numBands = 3; + const size_t frame = numRows * numCols; + /* + * Do this here since if it fails the whole function aborts and there is + * no chance to clean-up + */ + mxImageArray = + mxCreateNumericArray(3, dims, mxUINT8_CLASS, mxREAL); + + /* Create the sub-window - will fail internally if error */ + subWindow = createSubWindow(startRow, startCol, + numRows, numCols, numBands); + + buffers[0] = ((nitf_Uint8*)mxGetData(mxImageArray)); + buffers[1] = ((nitf_Uint8*)mxGetData(mxImageArray)) + frame; + buffers[2] = ((nitf_Uint8*)mxGetData(mxImageArray)) + 2 * frame; + /* Image reader (could fail) */ + imageReader = nitf_Reader_newImageReader(reader, idx, NULL, error); + if (!imageReader) + goto CATCH_ERROR; + + /* Now read the data */ + if (!nitf_ImageReader_read(imageReader, subWindow, + buffers, &padded, error)) + goto CATCH_ERROR; + + if(subWindow != NULL) + nitf_SubWindow_destruct(&subWindow); + if(imageReader != NULL) + nitf_ImageReader_destruct(&imageReader); + + return mxImageArray; + +CATCH_ERROR: + + if(subWindow != NULL) + nitf_SubWindow_destruct(&subWindow); + if(imageReader != NULL) + nitf_ImageReader_destruct(&imageReader); + if(mxImageArray != NULL); + mxFree(mxImageArray); + return NULL; +} + + + +/* + On error conditions, this function returns NULL and a const error string + via the errStr argument. It cannot call mexErrMsgTxt which pops back + to MATLAB without returning which would result in memory leaks +*/ +MEX_NTF_IMREAD findImageReader(nitf_ImageSegment* segment, + const char **errStr) +{ + /* Figure out if we have a float or a byte for now */ + int pixelDepth = + NITF_NBPP_TO_BYTES(NITF_ATO32(segment->subheader->NITF_NBPP->raw)); + + const char* pixelValue = segment->subheader->NITF_PVTYPE->raw; + + int numBands = NITF_ATO32(segment->subheader->NITF_NBANDS->raw); + + if(numBands == 1) /* One band, support 8-bit int and 32 bit float for now */ + { + if (pixelDepth == 1) + { + return &read8BitPixelArray; + } + else if (pixelDepth == 2) + { + return &read16BitPixelArray; + } + /* Deal with real mode */ + else if (memcmp(pixelValue, "R", 1) == 0 && pixelDepth == 4) + { + return &read32BitFloatPixelArray; + } + *errStr = + "Sorry, this MEX wrapper doesnt currently handle the pixel type"; + return(NULL); + } + else if(numBands == 2) + { + /* Complex IQ or MP + Look for IQ, 2 bands, with ICAT = {"SAR","SARIQ"} and ISUBCAT = {I,Q} + */ + if(memcmp(segment->subheader->NITF_ICAT->raw, "SAR", 3) == 0 + || memcmp(segment->subheader->NITF_ICAT->raw, "SARIQ", 5) == 0) + { + /* This is SAR, 2 bands */ + + char b0 = segment->subheader->bandInfo[0]->NITF_ISUBCAT->raw[0]; + char b1 = segment->subheader->bandInfo[1]->NITF_ISUBCAT->raw[0]; + + if((b0 == 'I') && (b1 == 'Q')) + { + /* + extra[0] = 0; + extra[1] = 1; + */ + } + /* + else if((b1 == 'I') && (b0 == 'Q')) + { + extra[1] = 0; + extra[0] = 1; + } + */ + else + { + *errStr = + "Sorry, this MEX wrapper doesnt currently handle the pixel type"; + return(NULL); + } + + if (pixelDepth == 4) /* Real*4 valued IQ complex */ + { + return &readIQComplexFloatPixelArray; + } + else if (pixelDepth == 2) + { + if (memcmp(pixelValue, "SI", 2) == 0) + { + return &readIQSignedIntPixelArray; + } + } + *errStr = + "Sorry, this MEX wrapper doesnt currently handle the pixel type"; + return(NULL); + } + } + else if (numBands == 3 && pixelDepth == 1) + { + if (memcmp(segment->subheader->NITF_IREP->raw, "RGB", 3) == 0) + { + return &read24BitPixelArray; + } + + } + *errStr = "Sorry, this MEX wrapper doesnt currently handle the pixel type"; + return NULL; +} + +/* + * Parse arguments + * + */ + +/* Returns true on success */ + +int parseArguments(int nrhs, const mxArray *prhs[], + char **inputFile, + int *idx, + long *startRow, + long *startCol, + long *numRows, + long *numCols, + const char **errStr) +{ + int argCount; /* Count of remaining arguments */ + int argIdx; /* Current argumetn index */ + char *key; /* Current keyword */ + char *plugin; /* Plugin path */ + nitf_Error error; /* For NITF library calls */ + +/* + +Initialize window values, use impossible values (0 for number of +rows/cols) to flag that window values are not supplied +*/ + + *startRow = 0; + *startCol = 0; + *numRows = 0; + *numCols = 0; + + *idx = 0; /* idx is zero based */ + + if(nrhs == 0) + { + *errStr = "At least one argument is required"; + return(0); + } + + *inputFile = newString(prhs[0]); + if(*inputFile == NULL) + { + *errStr = "Invalid keyword"; + return(0); + } + + + argCount = nrhs-1; /* Total remaining arguments */ + argIdx = 1; + while(argCount != 0) + { + key = mxArrayToString(prhs[argIdx]); + if(key == NULL) + { + *errStr = "Invalid keyword"; + free(*inputFile); + *inputFile = NULL; + return(0); + } + if(strcmp(key,"Segment") == 0) + { + argCount -= 1; + argIdx += 1; + if(argCount == 0) + { + mxFree(key); + *errStr = "Segment keyword requires an index value"; + free(*inputFile); + *inputFile = NULL; + return(0); + } + if(!mxIsNumeric(prhs[argIdx])) + { + mxFree(key); + *errStr = "Segment keyword requires an index value"; + free(*inputFile); + *inputFile = NULL; + return(0); + } + *idx = (int) (mxGetScalar(prhs[argIdx]) + 0.5); /* Paranoid ???*/ + *idx -= 1; /* Zero base */ + argCount -= 1; + argIdx += 1; + } + if(strcmp(key,"Plugins") == 0) + { + argCount -= 1; + argIdx += 1; + if(argCount == 0) + { + mxFree(key); + *errStr = "Segment keyword requires a string value"; + free(*inputFile); + *inputFile = NULL; + return(0); + } + + if((plugin = newString(prhs[argIdx])) == NULL) + { + mxFree(key); + *errStr = "Plugin keyword requires a string value"; + free(*inputFile); + *inputFile = NULL; + return(0); + } + if(!nitf_PluginRegistry_loadDir(plugin,&error) ) + { + *errStr = "Could not load NITF plugins"; + free(plugin); + mxFree(key); + free(*inputFile); + *inputFile = NULL; + return(0); + } + free(plugin); + + argCount -= 1; + argIdx += 1; + } + if(strcmp(key,"Window") == 0) + { + const mwSize *dims; /* Window spec dimensions */ + double *ptr; /* Pointer to dimensions */ + + argCount -= 1; + argIdx += 1; + if(argCount == 0) + { + *errStr = "Window keyword requires a row vector (4 values)"; + mxFree(key); + free(*inputFile); + *inputFile = NULL; + return(0); + } + if(!mxIsNumeric(prhs[argIdx])) + { + *errStr = "Window keyword requires a row vector (4 values)"; + mxFree(key); + free(*inputFile); + *inputFile = NULL; + return(0); + } + + dims = mxGetDimensions(prhs[argIdx]); + if((dims == NULL) || (dims[0] != 1) || (dims[1] != 4)) + { + *errStr = "Window keyword requires a row vector (4 values)"; + mxFree(key); + free(*inputFile); + *inputFile = NULL; + return(0); + } + + ptr = mxGetData(prhs[argIdx]); + + *startRow = (long) (ptr[0] + 0.5) - 1; /* Paranoid ???*/ + *startCol = (long) (ptr[1] + 0.5) - 1; + *numRows = (long) (ptr[2] + 0.5); + *numCols = (long) (ptr[3] + 0.5); + + argCount -= 1; + argIdx += 1; + } + mxFree(key); + } + return(1); +} + +/** + * The first thing to do here is read all of the nitf fields + * and then the TREs + */ +void mexFunction(int nlhs, mxArray *plhs[], + int nrhs, const mxArray *prhs[]) +{ + + /* Our nitf Reader */ + nitf_Reader* reader = NULL; + + /* The meta-data record */ + nitf_Record* record = NULL; + + /* Handle to the file */ + nitf_IOHandle io = NITF_INVALID_HANDLE_VALUE; + + /* Local error */ + nitf_Error error; + + /* Iterator for entry at idx */ + nitf_ListIterator it; + + /* Segment to be used */ + nitf_ImageSegment* segment = NULL; + + /* Pointer to input file name */ + char *inputFile = NULL; + + /* index */ + int idx; + int imageCount; /* Segment count (one based) */ + + /* Sub-window components */ + + long startRow; + long startCol; + long numRows; + long numCols; + long numRowsTotal; + long numColsTotal; + /* Error string */ + + const char *errStr; + + /* pointer to a function of value */ + MEX_NTF_IMREAD imread = NULL; + + mxArray* mxImageArray; + + if(!parseArguments(nrhs,prhs,&inputFile,&idx, + &startRow, &startCol, &numRows, &numCols, &errStr)) + { + mexErrMsgTxt(errStr); + return; + } + if(nlhs != 1) + { + free(inputFile); + mexErrMsgTxt("function requires exactly one output (struct)"); + return; + } + + /* Check that we have a NITF */ + if (nitf_Reader_getNITFVersion(inputFile) == NITF_VER_UNKNOWN) + { + free(inputFile); + mexErrMsgTxt("Input file is not NITF"); + return; + } + + /* Try to open this file */ + io = nitf_IOHandle_create(inputFile, + NITF_ACCESS_READONLY, + NITF_OPEN_EXISTING, + &error); + /* Get rid of this as soon as possible */ + free(inputFile); + + /* If the handle was bad, go home */ + if (NITF_INVALID_HANDLE(io)) + MEX_NTF_ERR(&error); + + /* Create the reader */ + reader = nitf_Reader_construct(&error); + if (!reader) + { + /* Close the handle and close up shop */ + nitf_IOHandle_close(io); + MEX_NTF_ERR(&error); + } + /* Read the meta-data */ + record = nitf_Reader_read(reader, io, &error); + + /* If the record was bad, start shutting down */ + if (!record) + { + nitf_Reader_destruct(&reader); + nitf_IOHandle_close(io); + MEX_NTF_ERR(&error); + } + +/* Get number of image segments from file header */ + + if(!nitf_Field_get(record->header->NITF_NUMI,(NITF_DATA *) &imageCount, + NITF_CONV_INT, sizeof(imageCount), &error)) + { + nitf_Reader_destruct(&reader); + nitf_Record_destruct(&record); + nitf_IOHandle_close(io); + MEX_NTF_ERR(&error); + } + + /* Check the image index argument which is one based, the segment count + is zero based */ + + if((idx < 0) || (idx > imageCount-1)) /*LJW*/ + { + nitf_Reader_destruct(&reader); + nitf_Record_destruct(&record); + nitf_IOHandle_close(io); + mexErrMsgTxt("Invalid image segment index"); + } + + /* Still rockin' */ + it = nitf_List_at(record->images, idx); + segment = (nitf_ImageSegment*)nitf_ListIterator_get(&it); + + /* TODO: Check most of the fields to make sure we are okay */ + imread = findImageReader(segment, &errStr); + + if (imread == NULL) + { + nitf_Reader_destruct(&reader); + nitf_Record_destruct(&record); + nitf_IOHandle_close(io); + mexErrMsgTxt(errStr); + } + + numRowsTotal = atol(segment->subheader->NITF_NROWS->raw); + numColsTotal = atol(segment->subheader->NITF_NCOLS->raw); + if(numRows == 0) /* No window specified, read full iamge */ + { + startRow = 0; + startCol = 0; + numRows = numRowsTotal; + numCols = numColsTotal; + } + /* Now validate the rectangle, and if its too big, resize to be nice */ + if (numRows + startRow > numRowsTotal) + { + numRows = numRowsTotal - startRow; + } + if (numCols + startCol > numColsTotal) + { + numCols = numColsTotal - startCol; + } + + mxImageArray = (*imread)(reader, idx,startRow, startCol, + numRows, numCols, &error); + + /* + Clean-up + + The image segment is part of the record so do not destruct it separately + */ + + if(reader != NULL) + nitf_Reader_destruct(&reader); + + if(record != NULL) + nitf_Record_destruct(&record); + + if(!NITF_INVALID_HANDLE(io)) + nitf_IOHandle_close(io); + + if(mxImageArray == NULL) + MEX_NTF_ERR(&error); + + plhs[0] = mxImageArray; + + return; +} + + diff --git a/modules/mex/nitf_image.def b/modules/mex/nitf_image.def new file mode 100644 index 000000000..0fde3ad43 --- /dev/null +++ b/modules/mex/nitf_image.def @@ -0,0 +1,2 @@ +LIBRARY nitf_image.mexw32 +EXPORTS mexFunction \ No newline at end of file diff --git a/modules/mex/nitf_metadata-64.def b/modules/mex/nitf_metadata-64.def new file mode 100644 index 000000000..89eef4828 --- /dev/null +++ b/modules/mex/nitf_metadata-64.def @@ -0,0 +1,2 @@ +LIBRARY nitf_metadata.mexw64 +EXPORTS mexFunction \ No newline at end of file diff --git a/modules/mex/nitf_metadata.c b/modules/mex/nitf_metadata.c new file mode 100644 index 000000000..2c705885e --- /dev/null +++ b/modules/mex/nitf_metadata.c @@ -0,0 +1,691 @@ +/* ========================================================================= + * This file is part of NITRO + * ========================================================================= + * + * (C) Copyright 2004 - 2010, General Dynamics - Advanced Information Systems + * + * NITRO is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ +#include +#include "mex.h" + +/* + * Error handling method + * + */ +#define MEX_NTF_ERR(E) \ + mexErrMsgTxt(( (E)->level == NITF_ERR_UNK) ? ("Unknown Error") : ( (E)->message)) + +/* + * Add a field from a nitf_Field* object into a mex object. + * The field in Matlab will have the name given by name. + */ +void addField(const char* name, mxArray* mexObj, nitf_Field* field) +{ + mxArray* mxStr = mxCreateString(field->raw); + int fNum = mxAddField(mexObj, name); + mxSetFieldByNumber(mexObj, 0, fNum, mxStr); +} + +/* + * Add a C-string into a mex object. + * The field in Matlab will have the name given by name. + */ +void addString(const char* name, mxArray* mexObj, const char* str) +{ + mxArray* mxStr = mxCreateString(str); + int fNum = mxAddField(mexObj, name); + mxSetFieldByNumber(mexObj, 0, fNum, mxStr); +} + +/* + * Create the NITF security record for any security section. + * This will use the generic names of the fields, since its + * allows us to reuse this function. + */ +static mxArray* createSecurityMx(nitf_FileSecurity* security) +{ + mxArray *mxSecurity = mxCreateStructMatrix(1, 1, 0, (const char**) NULL); + + addField("CLSY", mxSecurity, security->NITF_CLSY); + addField("CODE", mxSecurity, security->NITF_CODE); + addField("CTLH", mxSecurity, security->NITF_CTLH); + addField("REL", mxSecurity, security->NITF_REL); + addField("DCTP", mxSecurity, security->NITF_DCTP); + addField("DCDT", mxSecurity, security->NITF_DCDT); + addField("DCXM", mxSecurity, security->NITF_DCXM); + addField("DG", mxSecurity, security->NITF_DG); + addField("DGDT", mxSecurity, security->NITF_DGDT); + addField("CLTX", mxSecurity, security->NITF_CLTX); + addField("CATP", mxSecurity, security->NITF_CATP); + addField("CAUT", mxSecurity, security->NITF_CAUT); + addField("CRSN", mxSecurity, security->NITF_CRSN); + addField("RDT", mxSecurity, security->NITF_RDT); + addField("CTLN", mxSecurity, security->NITF_CTLN); + + return mxSecurity; +} + +/* + * Turn a TRE into an object. This will walk each value + * in the TRE. NITRO has a particular method for naming these + * and rather than try and be clever with the mex, I currently + * just search and replace the names when they are in NITRO's + * array notation: + * + * TRE_THING[0] => TRE_THING_0 + * + */ +static mxArray* createTREMx(nitf_TRE* tre) +{ + nitf_Error error; + nitf_TREEnumerator* it = NULL; + + mxArray *mxTRE = mxCreateStructMatrix(1, 1, 0, (const char**) NULL); + + addString("CETAG", mxTRE, tre->tag); + + it = nitf_TRE_begin(tre, &error); + + while (it && it->hasNext(&it)) + { + /* If this isn't set, it should have been an error */ + nitf_Pair* fieldPair = it->next(it, &error); + if (fieldPair) + { + nitf_Field* field = NULL; + /* Make a mutable copy of the key */ + char* key = (char*) malloc(strlen(fieldPair->key) + 1); + strcpy(key, fieldPair->key); + + /* Replace offending fields */ + nitf_Utils_replace(key, '[', '_'); + nitf_Utils_replace(key, ']', ' '); + nitf_Utils_trimString(key); + + /* Now set the key to the field */ + field = (nitf_Field*) fieldPair->data; + addField(key, mxTRE, field); + free(key); + } + else + nitf_Error_print(&error, stdout, "Field retrieval error"); + + } + addString("__treID__", mxTRE, nitf_TRE_getID(tre)); + + return mxTRE; +} + +/* + * Create the Extensions object as a cell-array. If there are no extensions, + * no big deal, they will be read in as an empty array anyway. + */ +static mxArray* createExtMx(nitf_Extensions* ext) +{ + int fNum = 0; + + /* Get the size of this cell array */ + int size = nitf_List_size(ext->ref); + + mxArray *mxExt = mxCreateCellMatrix(size, 1); + + nitf_ExtensionsIterator it; + nitf_ExtensionsIterator end; + + /* Loop through and count */ + it = nitf_Extensions_begin(ext); + end = nitf_Extensions_end(ext); + + while (nitf_ExtensionsIterator_notEqualTo(&it, &end)) + { + nitf_TRE* tre = (nitf_TRE*) nitf_ExtensionsIterator_get(&it); + + //fNum = mxAddField(mxExt, tre->name); + mxSetCell(mxExt, fNum++, createTREMx(tre)); + nitf_ExtensionsIterator_increment(&it); + } + + return mxExt; +} + +static mxArray* createImageCommentsMx(nitf_ImageSubheader* subheader) +{ + nitf_Error error; + int fNum = 0; + int size = 0; + nitf_ListIterator it = nitf_List_begin(subheader->imageComments); + nitf_ListIterator end = nitf_List_end(subheader->imageComments); + mxArray* mxList = NULL; + + /* Faster to look this up then iterate the list twice */ + + if (!nitf_Field_get(subheader->NITF_NICOM, &size, NITF_CONV_UINT, + NITF_INT32_SZ, &error)) + MEX_NTF_ERR(&error); + + mxList = mxCreateCellMatrix(size, 1); + + while (nitf_ListIterator_notEqualTo(&it, &end)) + { + nitf_Field* field = (nitf_Field*) nitf_ListIterator_get(&it); + mxArray* mxStr = mxCreateString(field->raw); + mxSetCell(mxList, fNum++, mxStr); + nitf_ListIterator_increment(&it); + } + return mxList; +} + +/* + * Create the header struct to convert the nitf_FileHeader + * This converts all fields over, and assumes that they + * are string-able. + */ +static mxArray* createHeaderMx(nitf_FileHeader* header) +{ + mxArray* tempArray = NULL; + int fNum = 0; + + mxArray *mxHeader = mxCreateStructMatrix(1, 1, 0, (const char**) NULL); + + addField("FHDR", mxHeader, header->NITF_FHDR); + addField("FVER", mxHeader, header->NITF_FVER); + addField("CLEVEL", mxHeader, header->NITF_CLEVEL); + addField("STYPE", mxHeader, header->NITF_STYPE); + addField("OSTAID", mxHeader, header->NITF_OSTAID); + addField("FDT", mxHeader, header->NITF_FDT); + addField("FTITLE", mxHeader, header->NITF_FTITLE); + addField("FSCLAS", mxHeader, header->NITF_FSCLAS); + + addField("FSCOP", mxHeader, header->NITF_FSCOP); + addField("FSCPYS", mxHeader, header->NITF_FSCPYS); + addField("ENCRYP", mxHeader, header->NITF_ENCRYP); + + /* Skip background color for now */ + + addField("ONAME", mxHeader, header->NITF_ONAME); + addField("OPHONE", mxHeader, header->NITF_OPHONE); + + addField("FL", mxHeader, header->NITF_FL); + addField("HL", mxHeader, header->NITF_HL); + addField("NUMI", mxHeader, header->NITF_NUMI); + addField("NUMS", mxHeader, header->NITF_NUMS); + addField("NUMX", mxHeader, header->NITF_NUMX); + addField("NUMT", mxHeader, header->NITF_NUMT); + addField("NUMDES", mxHeader, header->NITF_NUMDES); + addField("NUMRES", mxHeader, header->NITF_NUMRES); + + addField("UDHDL", mxHeader, header->NITF_UDHDL); + addField("UDHOFL", mxHeader, header->NITF_UDHOFL); + addField("XHDL", mxHeader, header->NITF_XHDL); + addField("XHDLOFL", mxHeader, header->NITF_XHDLOFL); + + fNum = mxAddField(mxHeader, "FS"); + mxSetFieldByNumber(mxHeader, 0, fNum, + createSecurityMx(header->securityGroup)); + + fNum = mxAddField(mxHeader, "UDHD"); + mxSetFieldByNumber(mxHeader, 0, fNum, + createExtMx(header->userDefinedSection)); + + fNum = mxAddField(mxHeader, "XHD"); + mxSetFieldByNumber(mxHeader, 0, fNum, createExtMx(header->extendedSection)); + + return mxHeader; +} + +static mxArray* createBandInfoMx(nitf_BandInfo* bandInfo) +{ + mxArray *mxBandInfo = mxCreateStructMatrix(1, 1, 0, (const char**) NULL); + + addField("IREPBAND", mxBandInfo, bandInfo->NITF_IREPBAND); + addField("ISUBCAT", mxBandInfo, bandInfo->NITF_ISUBCAT); + addField("IFC", mxBandInfo, bandInfo->NITF_IFC); + addField("IMFLT", mxBandInfo, bandInfo->NITF_IMFLT); + addField("NLUTS", mxBandInfo, bandInfo->NITF_NLUTS); + addField("NELUT", mxBandInfo, bandInfo->NITF_NELUT); + return mxBandInfo; +} + +static mxArray* createBandInfoArrayMx(nitf_ImageSubheader* subheader) +{ + int fNum = 0; + int size; + nitf_Error error; + mxArray* mxList; + + /* First figure out how many band info's we are going to allocate */ + size = nitf_ImageSubheader_getBandCount(subheader, &error); + if (size == NITF_INVALID_BAND_COUNT) + MEX_NTF_ERR(&error); + + mxList = mxCreateCellMatrix(size, 1); + + /* Go through each band info and make a struct */ + + for (fNum = 0; fNum < size; fNum++) + { + nitf_BandInfo* bandInfo = nitf_ImageSubheader_getBandInfo(subheader, + fNum, &error); + if (bandInfo == NULL) + MEX_NTF_ERR(&error); + + mxSetCell(mxList, fNum++, createBandInfoMx(bandInfo)); + } + + return mxList; +} + +static mxArray* createImageSubheaderMx(nitf_ImageSubheader* subheader) +{ + int fNum = 0; + mxArray *mxSubheader = mxCreateStructMatrix(1, 1, 0, (const char**) NULL); + + addField("IM", mxSubheader, subheader->NITF_IM); + addField("IID1", mxSubheader, subheader->NITF_IID1); + addField("IDATIM", mxSubheader, subheader->NITF_IDATIM); + addField("TGTID", mxSubheader, subheader->NITF_TGTID); + addField("IID2", mxSubheader, subheader->NITF_IID2); + addField("ISCLAS", mxSubheader, subheader->NITF_ISCLAS); + + fNum = mxAddField(mxSubheader, "IS"); + mxSetFieldByNumber(mxSubheader, 0, fNum, + createSecurityMx(subheader->securityGroup)); + + addField("ENCRYP", mxSubheader, subheader->NITF_ENCRYP); + addField("ISORCE", mxSubheader, subheader->NITF_ISORCE); + + addField("NROWS", mxSubheader, subheader->NITF_NROWS); + addField("NCOLS", mxSubheader, subheader->NITF_NCOLS); + + addField("PVTYPE", mxSubheader, subheader->NITF_PVTYPE); + addField("IREP", mxSubheader, subheader->NITF_IREP); + addField("ICAT", mxSubheader, subheader->NITF_ICAT); + + addField("ABPP", mxSubheader, subheader->NITF_ABPP); + + addField("PJUST", mxSubheader, subheader->NITF_PJUST); + addField("ICORDS", mxSubheader, subheader->NITF_ICORDS); + addField("IGEOLO", mxSubheader, subheader->NITF_IGEOLO); + + addField("NICOM", mxSubheader, subheader->NITF_NICOM); + + fNum = mxAddField(mxSubheader, "ICOM"); + mxSetFieldByNumber(mxSubheader, 0, fNum, createImageCommentsMx(subheader)); + + addField("IC", mxSubheader, subheader->NITF_IC); + addField("COMRAT", mxSubheader, subheader->NITF_COMRAT); + + addField("NBANDS", mxSubheader, subheader->NITF_NBANDS); + addField("XBANDS", mxSubheader, subheader->NITF_XBANDS); + + fNum = mxAddField(mxSubheader, "bands"); + mxSetFieldByNumber(mxSubheader, 0, fNum, createBandInfoArrayMx(subheader)); + + addField("ISYNC", mxSubheader, subheader->NITF_ISYNC); + addField("IMODE", mxSubheader, subheader->NITF_IMODE); + + addField("NBPR", mxSubheader, subheader->NITF_NBPR); + addField("NBPC", mxSubheader, subheader->NITF_NBPC); + addField("NPPBH", mxSubheader, subheader->NITF_NPPBH); + addField("NPPBV", mxSubheader, subheader->NITF_NPPBV); + addField("NBPP", mxSubheader, subheader->NITF_NBPP); + + addField("IDLVL", mxSubheader, subheader->NITF_IDLVL); + addField("IALVL", mxSubheader, subheader->NITF_IALVL); + addField("ILOC", mxSubheader, subheader->NITF_ILOC); + addField("IMAG", mxSubheader, subheader->NITF_IMAG); + + addField("UDIDL", mxSubheader, subheader->NITF_UDIDL); + addField("UDOFL", mxSubheader, subheader->NITF_UDOFL); + addField("IXSHDL", mxSubheader, subheader->NITF_IXSHDL); + addField("IXSOFL", mxSubheader, subheader->NITF_IXSOFL); + + fNum = mxAddField(mxSubheader, "UDID"); + mxSetFieldByNumber(mxSubheader, 0, fNum, + createExtMx(subheader->userDefinedSection)); + + fNum = mxAddField(mxSubheader, "XSHD"); + mxSetFieldByNumber(mxSubheader, 0, fNum, + createExtMx(subheader->extendedSection)); + + return mxSubheader; +} + +static mxArray* createGraphicSubheaderMx(nitf_GraphicSubheader* subheader) +{ + int fNum = 0; + mxArray *mxSubheader = mxCreateStructMatrix(1, 1, 0, (const char**) NULL); + + addField("SID", mxSubheader, subheader->NITF_SID); + addField("SNAME", mxSubheader, subheader->NITF_SNAME); + addField("SSCLAS", mxSubheader, subheader->NITF_SSCLAS); + + fNum = mxAddField(mxSubheader, "SS"); + mxSetFieldByNumber(mxSubheader, 0, fNum, + createSecurityMx(subheader->securityGroup)); + + addField("SFMT", mxSubheader, subheader->NITF_SFMT); + addField("SSTRUCT", mxSubheader, subheader->NITF_SSTRUCT); + addField("SDLVL", mxSubheader, subheader->NITF_SDLVL); + addField("SALVL", mxSubheader, subheader->NITF_SALVL); + addField("SLOC", mxSubheader, subheader->NITF_SLOC); + addField("SBND1", mxSubheader, subheader->NITF_SBND1); + addField("SCOLOR", mxSubheader, subheader->NITF_SCOLOR); + addField("SBND2", mxSubheader, subheader->NITF_SBND2); + addField("SRES2", mxSubheader, subheader->NITF_SRES2); + addField("SXSHDL", mxSubheader, subheader->NITF_SXSHDL); + addField("SXSOFL", mxSubheader, subheader->NITF_SXSOFL); + + fNum = mxAddField(mxSubheader, "SXSHD"); + mxSetFieldByNumber(mxSubheader, 0, fNum, + createExtMx(subheader->extendedSection)); + + return mxSubheader; +} + +static mxArray* createTextSubheaderMx(nitf_TextSubheader* subheader) +{ + int fNum = 0; + mxArray *mxSubheader = mxCreateStructMatrix(1, 1, 0, (const char**) NULL); + + addField("TE", mxSubheader, subheader->NITF_TE); + addField("TEXTID", mxSubheader, subheader->NITF_TEXTID); + addField("TXTALVL", mxSubheader, subheader->NITF_TXTALVL); + addField("TXTDT", mxSubheader, subheader->NITF_TXTDT); + addField("TXTITL", mxSubheader, subheader->NITF_TXTITL); + addField("TSCLAS", mxSubheader, subheader->NITF_TSCLAS); + + fNum = mxAddField(mxSubheader, "TS"); + mxSetFieldByNumber(mxSubheader, 0, fNum, + createSecurityMx(subheader->securityGroup)); + + addField("ENCRYP", mxSubheader, subheader->NITF_ENCRYP); + addField("TXTFMT", mxSubheader, subheader->NITF_TXTFMT); + addField("TXSHDL", mxSubheader, subheader->NITF_TXSHDL); + addField("TXSOFL", mxSubheader, subheader->NITF_TXSOFL); + + fNum = mxAddField(mxSubheader, "TXSHD"); + mxSetFieldByNumber(mxSubheader, 0, fNum, + createExtMx(subheader->extendedSection)); + + return mxSubheader; +} + +static mxArray* createDESubheaderMx(nitf_DESubheader* subheader) +{ + int fNum = 0; + mxArray *mxSubheader = mxCreateStructMatrix(1, 1, 0, (const char**) NULL); + + addField("DE", mxSubheader, subheader->filePartType); + addField("DESTAG", mxSubheader, subheader->NITF_DESTAG); + addField("DESVER", mxSubheader, subheader->NITF_DESVER); + addField("DESCLAS", mxSubheader, subheader->NITF_DESCLAS); + + fNum = mxAddField(mxSubheader, "DES"); + mxSetFieldByNumber(mxSubheader, 0, fNum, + createSecurityMx(subheader->securityGroup)); + + addField("DESOFLW", mxSubheader, subheader->NITF_DESOFLW); + addField("DESITEM", mxSubheader, subheader->NITF_DESITEM); + addField("DESSHL", mxSubheader, subheader->NITF_DESSHL); + + fNum = mxAddField(mxSubheader, "DESDATA"); + mxSetFieldByNumber(mxSubheader, 0, fNum, + createExtMx(subheader->userDefinedSection)); + + return mxSubheader; +} + +/* + * Create the Matlab struct to represent the Record. + * This will create separate structs for each of the + * sub-items + * + */ +static mxArray* createRecordMx(nitf_Record* record) +{ + nitf_Error error; + int fNum = 0; + int size = 0; + nitf_ListIterator it; + nitf_ListIterator end; + + mxArray *mxList = NULL; + mxArray *mxRecord = mxCreateStructMatrix(1, 1, 0, (const char**) NULL); + + mxArray* mxStr = NULL; + mxArray* mxHeader = NULL; + + fNum = mxAddField(mxRecord, "header"); + mxHeader = createHeaderMx(record->header); + mxSetFieldByNumber(mxRecord, 0, fNum, mxHeader); + + /* images */ + { + size = nitf_Record_getNumImages(record, &error); + mxList = mxCreateCellMatrix(size, 1); + + it = nitf_List_begin(record->images); + end = nitf_List_end(record->images); + + fNum = 0; + while (nitf_ListIterator_notEqualTo(&it, &end)) + { + nitf_ImageSegment* imageSegment = + (nitf_ImageSegment*) nitf_ListIterator_get(&it); + mxSetCell(mxList, fNum++, + createImageSubheaderMx(imageSegment->subheader)); + nitf_ListIterator_increment(&it); + } + + /* Now add our cell matrix to the record */ + fNum = mxAddField(mxRecord, "images"); + mxSetFieldByNumber(mxRecord, 0, fNum, mxList); + } + + /* graphics */ + { + size = nitf_Record_getNumGraphics(record, &error); + mxList = mxCreateCellMatrix(size, 1); + + it = nitf_List_begin(record->graphics); + end = nitf_List_end(record->graphics); + + fNum = 0; + while (nitf_ListIterator_notEqualTo(&it, &end)) + { + nitf_GraphicSegment* segment = + (nitf_GraphicSegment*) nitf_ListIterator_get(&it); + mxSetCell(mxList, fNum++, + createGraphicSubheaderMx(segment->subheader)); + nitf_ListIterator_increment(&it); + } + + /* Now add our cell matrix to the record */ + fNum = mxAddField(mxRecord, "graphics"); + mxSetFieldByNumber(mxRecord, 0, fNum, mxList); + } + + /* texts */ + { + size = nitf_Record_getNumTexts(record, &error); + mxList = mxCreateCellMatrix(size, 1); + + it = nitf_List_begin(record->texts); + end = nitf_List_end(record->texts); + + fNum = 0; + while (nitf_ListIterator_notEqualTo(&it, &end)) + { + nitf_TextSegment* segment = + (nitf_TextSegment*) nitf_ListIterator_get(&it); + mxSetCell(mxList, fNum++, createTextSubheaderMx(segment->subheader)); + nitf_ListIterator_increment(&it); + } + + /* Now add our cell matrix to the record */ + fNum = mxAddField(mxRecord, "texts"); + mxSetFieldByNumber(mxRecord, 0, fNum, mxList); + } + + /* DES */ + { + size = nitf_Record_getNumDataExtensions(record, &error); + mxList = mxCreateCellMatrix(size, 1); + + it = nitf_List_begin(record->dataExtensions); + end = nitf_List_end(record->dataExtensions); + + fNum = 0; + while (nitf_ListIterator_notEqualTo(&it, &end)) + { + nitf_DESegment* segment = + (nitf_DESegment*) nitf_ListIterator_get(&it); + mxSetCell(mxList, fNum++, createDESubheaderMx(segment->subheader)); + nitf_ListIterator_increment(&it); + } + + /* Now add our cell matrix to the record */ + fNum = mxAddField(mxRecord, "dataExtensions"); + mxSetFieldByNumber(mxRecord, 0, fNum, mxList); + } + + return mxRecord; +} + +/* + * Allocate a C-string from a Matlab array + */ +static char* newString(const mxArray* mx) +{ + size_t len; + char* str = NULL; + if (!mxIsChar(mx)) + mexErrMsgTxt("Require string arg"); + + if (mxGetM(mx) != 1) + mexErrMsgTxt("Input must be a row vector"); + + len = (mxGetM(mx) * mxGetN(mx)) + 1; + str = (char*) malloc(len + 1); + str[len] = 0; + if (mxGetString(mx, str, len) != 0) + { + free(str); + mexErrMsgTxt("Not enough space!"); + } + return str; +} + +/** + * The first thing to do here is read all of the nitf fields + * and then the TREs + */ +void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) +{ + + /* Our nitf Reader */ + nitf_Reader* reader; + + /* The meta-data record */ + nitf_Record* record; + + /* Handle to the file */ + nitf_IOHandle io; + + /* Local error */ + nitf_Error error; + + /* Pointer to input file name */ + char *inputFile = NULL; + + /* Returned array */ + mxArray* mxRecord = NULL; + + if (nrhs != 1 && nrhs != 2) + { + mexErrMsgTxt(" (nitf-plugin-path)"); + return; + } + + if (nrhs == 2) + { + char* pluginPath = newString(prhs[1]); + /* Alternative to NITF_PLUGIN_PATH */ + if (!nitf_PluginRegistry_loadDir(pluginPath, &error)) + { + free(pluginPath); + MEX_NTF_ERR(&error); + } + free(pluginPath); + } + + /* Output will be a single struct */ + else if (nlhs > 1) + { + mexErrMsgTxt("function requires only one output (struct)"); + return; + } + + /* Set input file (copy) */ + inputFile = newString(prhs[0]); + + /* Check that we have a NITF */ + if (nitf_Reader_getNITFVersion(inputFile) == NITF_VER_UNKNOWN) + { + mexErrMsgTxt(inputFile); + free(inputFile); + return; + + } + + /* Try to open this file */ + io = nitf_IOHandle_create(inputFile, NITF_ACCESS_READONLY, + NITF_OPEN_EXISTING, &error); + + /* Get rid of this as soon as possible */ + free(inputFile); + + /* If the handle was bad, go home */ + if (NITF_INVALID_HANDLE(io)) + MEX_NTF_ERR(&error); + + /* Create the reader */ + reader = nitf_Reader_construct(&error); + if (!reader) + { + /* Close the handle and close up shop */ + nitf_IOHandle_close(io); + MEX_NTF_ERR(&error); + + } + /* Read the meta-data */ + record = nitf_Reader_read(reader, io, &error); + + /* If the record was bad, start shutting down */ + if (!record) + { + nitf_Reader_destruct(&reader); + nitf_IOHandle_close(io); + MEX_NTF_ERR(&error); + } + + /* Still rockin' */ + mxRecord = createRecordMx(record); + plhs[0] = mxRecord; +} + diff --git a/modules/mex/nitf_metadata.def b/modules/mex/nitf_metadata.def new file mode 100644 index 000000000..c4e2cf564 --- /dev/null +++ b/modules/mex/nitf_metadata.def @@ -0,0 +1,2 @@ +LIBRARY nitf_metadata.mexw32 +EXPORTS mexFunction \ No newline at end of file diff --git a/modules/mex/wscript b/modules/mex/wscript new file mode 100644 index 000000000..d2286f508 --- /dev/null +++ b/modules/mex/wscript @@ -0,0 +1,7 @@ +options = distclean = configure = lambda x: None + +def build(bld): + for src in 'nitf_image.c nitf_metadata.c'.split(): + bld.mexify(source=src, uselib_local='nitf-c', lang='c') + + bld.mexify(source='xml_metadata.cpp', module_deps='xml.lite nitf') diff --git a/modules/mex/xml_metadata-64.def b/modules/mex/xml_metadata-64.def new file mode 100644 index 000000000..85bdb67e7 --- /dev/null +++ b/modules/mex/xml_metadata-64.def @@ -0,0 +1,2 @@ +LIBRARY xml_metadata.mexw64 +EXPORTS mexFunction \ No newline at end of file diff --git a/modules/mex/xml_metadata.cpp b/modules/mex/xml_metadata.cpp new file mode 100644 index 000000000..a4eec8d8e --- /dev/null +++ b/modules/mex/xml_metadata.cpp @@ -0,0 +1,351 @@ +/*! + * This matlab function gets XML out of (almost) anywhere, and turns + * it into a matlab cell matrix. + * + * For most typical users, you just pass in an XML file and this function + * will reorganize the file into a hierarchical matlab struct. + * + * This function also supports reading XML in from the DES segment of + * a NITF. In that case, there may be more than one XML structure coming + * back. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#if defined(WIN32) +# if _MSC_VER < 1600 + typedef wchar_t char16_t; +# else +# define __STDC_UTF_16__ +# endif +#endif +#include "mex.h" + +using namespace sys; +using namespace xml::lite; + +extern void _main(); + +// This is just to keep track of things +typedef std::map Count_T; + +// This is to get a count of all unique children of this node +static void getUniqueChildrenCount(xml::lite::Element* element, + Count_T& count) +{ + int numChildren = element->getChildren().size(); + + for (int i = 0; i < numChildren; i++) + { + xml::lite::Element* child = element->getChildren()[i]; + count[ child->getLocalName() ]++; + } + return; + +} + +// Does the work +static mxArray* createMx(xml::lite::Element* element) +{ + // Total size is numChildren + offset + int offset = 0; + + // We will use this to store data associated with this elem + std::map data; + + int i = 0; + + // This is a data structure that lists children + Count_T childCount; + + // Get a listing of each count of children + getUniqueChildrenCount( element, childCount ); + + + // The number of unique children + int numChildren = childCount.size(); + //std::cout << "Num unique elements: " << numChildren << std::endl; + + // This is the tag character data + std::string str = element->getCharacterData(); + + // If the body is empty, no CD + if (!str.empty()) + { + // Otherwise add it to our data for this element + data[ std::string("characters") ] = str; + + // Add a child for the data + offset++; + } + + xml::lite::Attributes atts = element->getAttributes(); + for (i = 0; i < atts.getLength(); i++) + { + std::string attVal = atts[i].getValue(); + if (!attVal.empty()) + { + std::string localName = atts[i].getLocalName() + "Attr"; + data[ localName ] = attVal; + offset++; + } + } + + // Our number of unique fields is going to be the unique children + // plus the data components + const int numberOfFields = numChildren + offset; + + // Attributes goes in data too + char** names = new char*[numberOfFields]; + + // Reset i + i = 0; + // For each unique tag name + for (std::map::const_iterator p = + childCount.begin(); p != childCount.end(); ++p) + { + // Get it + std::string fieldName = p->first; + // Set it + names[i] = new char[fieldName.length() + 1]; + // Copy it + strcpy(names[i], fieldName.c_str()); + i++; + } + + // Also have to do the same for each data component + // Notice we are not resetting i + if (offset) + { + for (std::map::const_iterator it = + data.begin(); it != data.end(); ++it) + { + // Add something here + names[i] = new char[it->first.length() + 1]; + strcpy(names[i], it->first.c_str()); + i++; + } + } + // Now allocate the struct, since we can + mxArray* structArrayPtr = + mxCreateStructMatrix(1, 1, numberOfFields, (const char**)names); + + // Reset i + i = 0; + + // Now go through each unique field + for (std::map::const_iterator p = + childCount.begin(); p != childCount.end(); ++p) + { + + // Get it + std::string fieldName = p->first; + + // Num times it happens + int count = p->second; + + mxArray* childPtr = NULL; + // Get the vector of elements + std::vector sameElements; + element->getElementsByTagName( fieldName, sameElements ); + + + // If there are multiple elements, create a cell matrix + // 1xN + // We need to do this whole rigamorale for each child + childPtr = mxCreateCellMatrix(count, 1); + for (int j = 0; j < count; j++) + { + mxSetCell(childPtr, j, createMx(sameElements[j])); + } + + mxSetField(structArrayPtr, 0, + names[i], + childPtr); + i++; + } + + + if (offset) + { + assert( data.size() + i == numberOfFields); + assert( numberOfFields == mxGetNumberOfFields(structArrayPtr) ); + for (std::map::const_iterator it = + data.begin(); it != data.end(); ++it) + { + + mxSetField(structArrayPtr, 0, + it->first.c_str(), mxCreateString(it->second.c_str())); + + i++; + } + } + + for (i = 0; i < numberOfFields; i++) + { + delete [] names[i]; + } + delete [] names; + + return structArrayPtr; +} + +static mxArray* createStruct(xml::lite::Element* root) +{ + const char* fieldNames[] = { root->getLocalName().c_str() }; + mxArray* structArrayPtr = mxCreateStructMatrix(1, 1, 1, fieldNames); + + mxArray* structArrayChildPtr = createMx( root ); + + mxSetField(structArrayPtr, 0, + fieldNames[0], + structArrayChildPtr); + + return structArrayPtr; +} + +static std::string getString(const mxArray* mx) +{ + if (!mxIsChar(mx)) + throw except::Exception(Ctxt("Require string arg")); + + if (mxGetM(mx) != 1) + throw except::Exception(Ctxt("Input must be a row vector")); + + + size_t len = (mxGetM(mx) * mxGetN(mx)) + 1; + char* buf = new char[len]; + if (mxGetString(mx, buf, len) != 0) + { + delete [] buf; + throw except::Exception(Ctxt("Not enough space!")); + } + std::string s(buf); + delete [] buf; + return s; + +} + + +class IOInputStreamAdapter : public ::io::InputStream +{ + + nitf::SegmentReader& mReader; +public: + + IOInputStreamAdapter(nitf::SegmentReader& reader) : mReader(reader) {} + ~IOInputStreamAdapter() {} + + virtual sys::Off_T available() + { + return (sys::Off_T)mReader.getSize(); + } + + virtual sys::SSize_T read(sys::byte* b, sys::Size_T len) + { + mReader.read((NITF_DATA*)b, len); + return len; + } +}; + +void mexFunction(int nlhs, mxArray *plhs[], + int nrhs, const mxArray *prhs[]) +{ + + if (nrhs != 1 && nrhs != 5) + { + mexErrMsgTxt(""); + return; + } + else if (nlhs > 1) + { + mexErrMsgTxt("function requires only one output (struct)"); + return; + } + try + { + + std::string inputFile = getString(prhs[0]); + + Document* doc = NULL; + + // Must not be a NITF -- maybe its an XML file + // For now this is a feature of the function + if (nitf::Reader::getNITFVersion(inputFile) == NITF_VER_UNKNOWN) + { + xml::lite::MinidomParser parser; + ::io::FileInputStream fis( inputFile ); + parser.parse( fis ); + xml::lite::Document* doc = parser.getDocument(); + // We are going out of scope at the end of this brace + + Element* root = doc->getRootElement(); + plhs[0] = createStruct( root ); + + fis.close(); + } + else + { + nitf::Reader reader; + nitf::IOHandle io(inputFile); + nitf::Record record = reader.read(io); + nitf::List des = record.getDataExtensions(); + nitf::Uint32 numDES = des.getSize(); + std::vector structs; + + for (nitf::Uint32 i = 0; i < numDES; i++) + { + nitf::DESegment seg = des[i]; + nitf::DESubheader subheader = seg.getSubheader(); + std::string desid = subheader.getTypeID().toString(); + str::trim(desid); + + + if (str::endsWith(desid, "XML")) + { + try + { + nitf::SegmentReader deReader = reader.newDEReader(i); + IOInputStreamAdapter ioAdapter(deReader); + xml::lite::MinidomParser xmlParser; + xmlParser.parse(ioAdapter); + xml::lite::Document* doc = xmlParser.getDocument(); + Element* root = doc->getRootElement(); + + mxArray* xmlStruct = createStruct( root ); + structs.push_back(xmlStruct); + + } + catch (except::Exception& e) + { + std::cout << "Failed to parse segment. Skipping [" << desid << "]. " << e.getMessage() << std::endl; + + } + } + // Now join them all together into one big LHS + + } + mxArray* allPtr = mxCreateCellMatrix( structs.size(), 1); + for (unsigned int i = 0; i < structs.size(); i++) + { + mxSetCell(allPtr, i, structs[i]); + } + plhs[0] = allPtr; + } + + + + } + catch (except::Exception& e) + { + mexErrMsgTxt(e.getMessage().c_str()); + } +} + diff --git a/modules/mex/xml_metadata.def b/modules/mex/xml_metadata.def new file mode 100644 index 000000000..812ab9cb9 --- /dev/null +++ b/modules/mex/xml_metadata.def @@ -0,0 +1,2 @@ +LIBRARY xml_metadata.mexw32 +EXPORTS mexFunction \ No newline at end of file