├── AUTHORS ├── COPYING ├── ChangeLog ├── INSTALL ├── Makefile.am ├── Makefile.in ├── NEWS ├── README ├── README.md ├── aclocal.m4 ├── compile ├── configure ├── configure.ac ├── depcomp ├── install-sh ├── m4 └── ax_cxx_compile_stdcxx_11.m4 ├── missing └── src ├── Makefile.am ├── Makefile.in ├── dsffile.cpp ├── dsffile.h ├── dsfheader.cpp ├── dsfheader.h ├── dsfproperties.cpp ├── dsfproperties.h ├── main.cpp ├── metadsf.cpp ├── metadsf.h ├── mkdsf.cpp ├── optionparser.h ├── options.cpp ├── options.h ├── typedefs.h ├── utils.cpp └── utils.h /AUTHORS: -------------------------------------------------------------------------------- 1 | Peking Duck (pekingducklabs@gmail.com) 2 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | Version 0.1 released on April 2, 2013 2 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | Installation Instructions 2 | ************************* 3 | 4 | Copyright (C) 1994-1996, 1999-2002, 2004-2013 Free Software Foundation, 5 | Inc. 6 | 7 | Copying and distribution of this file, with or without modification, 8 | are permitted in any medium without royalty provided the copyright 9 | notice and this notice are preserved. This file is offered as-is, 10 | without warranty of any kind. 11 | 12 | Basic Installation 13 | ================== 14 | 15 | Briefly, the shell command `./configure && make && make install' 16 | should configure, build, and install this package. The following 17 | more-detailed instructions are generic; see the `README' file for 18 | instructions specific to this package. Some packages provide this 19 | `INSTALL' file but do not implement all of the features documented 20 | below. The lack of an optional feature in a given package is not 21 | necessarily a bug. More recommendations for GNU packages can be found 22 | in *note Makefile Conventions: (standards)Makefile Conventions. 23 | 24 | The `configure' shell script attempts to guess correct values for 25 | various system-dependent variables used during compilation. It uses 26 | those values to create a `Makefile' in each directory of the package. 27 | It may also create one or more `.h' files containing system-dependent 28 | definitions. Finally, it creates a shell script `config.status' that 29 | you can run in the future to recreate the current configuration, and a 30 | file `config.log' containing compiler output (useful mainly for 31 | debugging `configure'). 32 | 33 | It can also use an optional file (typically called `config.cache' 34 | and enabled with `--cache-file=config.cache' or simply `-C') that saves 35 | the results of its tests to speed up reconfiguring. Caching is 36 | disabled by default to prevent problems with accidental use of stale 37 | cache files. 38 | 39 | If you need to do unusual things to compile the package, please try 40 | to figure out how `configure' could check whether to do them, and mail 41 | diffs or instructions to the address given in the `README' so they can 42 | be considered for the next release. If you are using the cache, and at 43 | some point `config.cache' contains results you don't want to keep, you 44 | may remove or edit it. 45 | 46 | The file `configure.ac' (or `configure.in') is used to create 47 | `configure' by a program called `autoconf'. You need `configure.ac' if 48 | you want to change it or regenerate `configure' using a newer version 49 | of `autoconf'. 50 | 51 | The simplest way to compile this package is: 52 | 53 | 1. `cd' to the directory containing the package's source code and type 54 | `./configure' to configure the package for your system. 55 | 56 | Running `configure' might take a while. While running, it prints 57 | some messages telling which features it is checking for. 58 | 59 | 2. Type `make' to compile the package. 60 | 61 | 3. Optionally, type `make check' to run any self-tests that come with 62 | the package, generally using the just-built uninstalled binaries. 63 | 64 | 4. Type `make install' to install the programs and any data files and 65 | documentation. When installing into a prefix owned by root, it is 66 | recommended that the package be configured and built as a regular 67 | user, and only the `make install' phase executed with root 68 | privileges. 69 | 70 | 5. Optionally, type `make installcheck' to repeat any self-tests, but 71 | this time using the binaries in their final installed location. 72 | This target does not install anything. Running this target as a 73 | regular user, particularly if the prior `make install' required 74 | root privileges, verifies that the installation completed 75 | correctly. 76 | 77 | 6. You can remove the program binaries and object files from the 78 | source code directory by typing `make clean'. To also remove the 79 | files that `configure' created (so you can compile the package for 80 | a different kind of computer), type `make distclean'. There is 81 | also a `make maintainer-clean' target, but that is intended mainly 82 | for the package's developers. If you use it, you may have to get 83 | all sorts of other programs in order to regenerate files that came 84 | with the distribution. 85 | 86 | 7. Often, you can also type `make uninstall' to remove the installed 87 | files again. In practice, not all packages have tested that 88 | uninstallation works correctly, even though it is required by the 89 | GNU Coding Standards. 90 | 91 | 8. Some packages, particularly those that use Automake, provide `make 92 | distcheck', which can by used by developers to test that all other 93 | targets like `make install' and `make uninstall' work correctly. 94 | This target is generally not run by end users. 95 | 96 | Compilers and Options 97 | ===================== 98 | 99 | Some systems require unusual options for compilation or linking that 100 | the `configure' script does not know about. Run `./configure --help' 101 | for details on some of the pertinent environment variables. 102 | 103 | You can give `configure' initial values for configuration parameters 104 | by setting variables in the command line or in the environment. Here 105 | is an example: 106 | 107 | ./configure CC=c99 CFLAGS=-g LIBS=-lposix 108 | 109 | *Note Defining Variables::, for more details. 110 | 111 | Compiling For Multiple Architectures 112 | ==================================== 113 | 114 | You can compile the package for more than one kind of computer at the 115 | same time, by placing the object files for each architecture in their 116 | own directory. To do this, you can use GNU `make'. `cd' to the 117 | directory where you want the object files and executables to go and run 118 | the `configure' script. `configure' automatically checks for the 119 | source code in the directory that `configure' is in and in `..'. This 120 | is known as a "VPATH" build. 121 | 122 | With a non-GNU `make', it is safer to compile the package for one 123 | architecture at a time in the source code directory. After you have 124 | installed the package for one architecture, use `make distclean' before 125 | reconfiguring for another architecture. 126 | 127 | On MacOS X 10.5 and later systems, you can create libraries and 128 | executables that work on multiple system types--known as "fat" or 129 | "universal" binaries--by specifying multiple `-arch' options to the 130 | compiler but only a single `-arch' option to the preprocessor. Like 131 | this: 132 | 133 | ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ 134 | CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ 135 | CPP="gcc -E" CXXCPP="g++ -E" 136 | 137 | This is not guaranteed to produce working output in all cases, you 138 | may have to build one architecture at a time and combine the results 139 | using the `lipo' tool if you have problems. 140 | 141 | Installation Names 142 | ================== 143 | 144 | By default, `make install' installs the package's commands under 145 | `/usr/local/bin', include files under `/usr/local/include', etc. You 146 | can specify an installation prefix other than `/usr/local' by giving 147 | `configure' the option `--prefix=PREFIX', where PREFIX must be an 148 | absolute file name. 149 | 150 | You can specify separate installation prefixes for 151 | architecture-specific files and architecture-independent files. If you 152 | pass the option `--exec-prefix=PREFIX' to `configure', the package uses 153 | PREFIX as the prefix for installing programs and libraries. 154 | Documentation and other data files still use the regular prefix. 155 | 156 | In addition, if you use an unusual directory layout you can give 157 | options like `--bindir=DIR' to specify different values for particular 158 | kinds of files. Run `configure --help' for a list of the directories 159 | you can set and what kinds of files go in them. In general, the 160 | default for these options is expressed in terms of `${prefix}', so that 161 | specifying just `--prefix' will affect all of the other directory 162 | specifications that were not explicitly provided. 163 | 164 | The most portable way to affect installation locations is to pass the 165 | correct locations to `configure'; however, many packages provide one or 166 | both of the following shortcuts of passing variable assignments to the 167 | `make install' command line to change installation locations without 168 | having to reconfigure or recompile. 169 | 170 | The first method involves providing an override variable for each 171 | affected directory. For example, `make install 172 | prefix=/alternate/directory' will choose an alternate location for all 173 | directory configuration variables that were expressed in terms of 174 | `${prefix}'. Any directories that were specified during `configure', 175 | but not in terms of `${prefix}', must each be overridden at install 176 | time for the entire installation to be relocated. The approach of 177 | makefile variable overrides for each directory variable is required by 178 | the GNU Coding Standards, and ideally causes no recompilation. 179 | However, some platforms have known limitations with the semantics of 180 | shared libraries that end up requiring recompilation when using this 181 | method, particularly noticeable in packages that use GNU Libtool. 182 | 183 | The second method involves providing the `DESTDIR' variable. For 184 | example, `make install DESTDIR=/alternate/directory' will prepend 185 | `/alternate/directory' before all installation names. The approach of 186 | `DESTDIR' overrides is not required by the GNU Coding Standards, and 187 | does not work on platforms that have drive letters. On the other hand, 188 | it does better at avoiding recompilation issues, and works well even 189 | when some directory options were not specified in terms of `${prefix}' 190 | at `configure' time. 191 | 192 | Optional Features 193 | ================= 194 | 195 | If the package supports it, you can cause programs to be installed 196 | with an extra prefix or suffix on their names by giving `configure' the 197 | option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. 198 | 199 | Some packages pay attention to `--enable-FEATURE' options to 200 | `configure', where FEATURE indicates an optional part of the package. 201 | They may also pay attention to `--with-PACKAGE' options, where PACKAGE 202 | is something like `gnu-as' or `x' (for the X Window System). The 203 | `README' should mention any `--enable-' and `--with-' options that the 204 | package recognizes. 205 | 206 | For packages that use the X Window System, `configure' can usually 207 | find the X include and library files automatically, but if it doesn't, 208 | you can use the `configure' options `--x-includes=DIR' and 209 | `--x-libraries=DIR' to specify their locations. 210 | 211 | Some packages offer the ability to configure how verbose the 212 | execution of `make' will be. For these packages, running `./configure 213 | --enable-silent-rules' sets the default to minimal output, which can be 214 | overridden with `make V=1'; while running `./configure 215 | --disable-silent-rules' sets the default to verbose, which can be 216 | overridden with `make V=0'. 217 | 218 | Particular systems 219 | ================== 220 | 221 | On HP-UX, the default C compiler is not ANSI C compatible. If GNU 222 | CC is not installed, it is recommended to use the following options in 223 | order to use an ANSI C compiler: 224 | 225 | ./configure CC="cc -Ae -D_XOPEN_SOURCE=500" 226 | 227 | and if that doesn't work, install pre-built binaries of GCC for HP-UX. 228 | 229 | HP-UX `make' updates targets which have the same time stamps as 230 | their prerequisites, which makes it generally unusable when shipped 231 | generated files such as `configure' are involved. Use GNU `make' 232 | instead. 233 | 234 | On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot 235 | parse its `' header file. The option `-nodtk' can be used as 236 | a workaround. If GNU CC is not installed, it is therefore recommended 237 | to try 238 | 239 | ./configure CC="cc" 240 | 241 | and if that doesn't work, try 242 | 243 | ./configure CC="cc -nodtk" 244 | 245 | On Solaris, don't put `/usr/ucb' early in your `PATH'. This 246 | directory contains several dysfunctional programs; working variants of 247 | these programs are available in `/usr/bin'. So, if you need `/usr/ucb' 248 | in your `PATH', put it _after_ `/usr/bin'. 249 | 250 | On Haiku, software installed for all users goes in `/boot/common', 251 | not `/usr/local'. It is recommended to use the following options: 252 | 253 | ./configure --prefix=/boot/common 254 | 255 | Specifying the System Type 256 | ========================== 257 | 258 | There may be some features `configure' cannot figure out 259 | automatically, but needs to determine by the type of machine the package 260 | will run on. Usually, assuming the package is built to be run on the 261 | _same_ architectures, `configure' can figure that out, but if it prints 262 | a message saying it cannot guess the machine type, give it the 263 | `--build=TYPE' option. TYPE can either be a short name for the system 264 | type, such as `sun4', or a canonical name which has the form: 265 | 266 | CPU-COMPANY-SYSTEM 267 | 268 | where SYSTEM can have one of these forms: 269 | 270 | OS 271 | KERNEL-OS 272 | 273 | See the file `config.sub' for the possible values of each field. If 274 | `config.sub' isn't included in this package, then this package doesn't 275 | need to know the machine type. 276 | 277 | If you are _building_ compiler tools for cross-compiling, you should 278 | use the option `--target=TYPE' to select the type of system they will 279 | produce code for. 280 | 281 | If you want to _use_ a cross compiler, that generates code for a 282 | platform different from the build platform, you should specify the 283 | "host" platform (i.e., that on which the generated programs will 284 | eventually be run) with `--host=TYPE'. 285 | 286 | Sharing Defaults 287 | ================ 288 | 289 | If you want to set default values for `configure' scripts to share, 290 | you can create a site shell script called `config.site' that gives 291 | default values for variables like `CC', `cache_file', and `prefix'. 292 | `configure' looks for `PREFIX/share/config.site' if it exists, then 293 | `PREFIX/etc/config.site' if it exists. Or, you can set the 294 | `CONFIG_SITE' environment variable to the location of the site script. 295 | A warning: not all `configure' scripts look for a site script. 296 | 297 | Defining Variables 298 | ================== 299 | 300 | Variables not defined in a site shell script can be set in the 301 | environment passed to `configure'. However, some packages may run 302 | configure again during the build, and the customized values of these 303 | variables may be lost. In order to avoid this problem, you should set 304 | them in the `configure' command line, using `VAR=value'. For example: 305 | 306 | ./configure CC=/usr/local2/bin/gcc 307 | 308 | causes the specified `gcc' to be used as the C compiler (unless it is 309 | overridden in the site shell script). 310 | 311 | Unfortunately, this technique does not work for `CONFIG_SHELL' due to 312 | an Autoconf limitation. Until the limitation is lifted, you can use 313 | this workaround: 314 | 315 | CONFIG_SHELL=/bin/bash ./configure CONFIG_SHELL=/bin/bash 316 | 317 | `configure' Invocation 318 | ====================== 319 | 320 | `configure' recognizes the following options to control how it 321 | operates. 322 | 323 | `--help' 324 | `-h' 325 | Print a summary of all of the options to `configure', and exit. 326 | 327 | `--help=short' 328 | `--help=recursive' 329 | Print a summary of the options unique to this package's 330 | `configure', and exit. The `short' variant lists options used 331 | only in the top level, while the `recursive' variant lists options 332 | also present in any nested packages. 333 | 334 | `--version' 335 | `-V' 336 | Print the version of Autoconf used to generate the `configure' 337 | script, and exit. 338 | 339 | `--cache-file=FILE' 340 | Enable the cache: use and save the results of the tests in FILE, 341 | traditionally `config.cache'. FILE defaults to `/dev/null' to 342 | disable caching. 343 | 344 | `--config-cache' 345 | `-C' 346 | Alias for `--cache-file=config.cache'. 347 | 348 | `--quiet' 349 | `--silent' 350 | `-q' 351 | Do not print messages saying which checks are being made. To 352 | suppress all normal output, redirect it to `/dev/null' (any error 353 | messages will still be shown). 354 | 355 | `--srcdir=DIR' 356 | Look for the package's source code in directory DIR. Usually 357 | `configure' can determine that directory automatically. 358 | 359 | `--prefix=DIR' 360 | Use DIR as the installation prefix. *note Installation Names:: 361 | for more details, including other options available for fine-tuning 362 | the installation locations. 363 | 364 | `--no-create' 365 | `-n' 366 | Run the configure checks, but stop before creating any output 367 | files. 368 | 369 | `configure' also accepts some other, not widely useful, options. Run 370 | `configure --help' for more details. 371 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = src 2 | -------------------------------------------------------------------------------- /Makefile.in: -------------------------------------------------------------------------------- 1 | # Makefile.in generated by automake 1.14.1 from Makefile.am. 2 | # @configure_input@ 3 | 4 | # Copyright (C) 1994-2013 Free Software Foundation, Inc. 5 | 6 | # This Makefile.in is free software; the Free Software Foundation 7 | # gives unlimited permission to copy and/or distribute it, 8 | # with or without modifications, as long as this notice is preserved. 9 | 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY, to the extent permitted by law; without 12 | # even the implied warranty of MERCHANTABILITY or FITNESS FOR A 13 | # PARTICULAR PURPOSE. 14 | 15 | @SET_MAKE@ 16 | VPATH = @srcdir@ 17 | am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' 18 | am__make_running_with_option = \ 19 | case $${target_option-} in \ 20 | ?) ;; \ 21 | *) echo "am__make_running_with_option: internal error: invalid" \ 22 | "target option '$${target_option-}' specified" >&2; \ 23 | exit 1;; \ 24 | esac; \ 25 | has_opt=no; \ 26 | sane_makeflags=$$MAKEFLAGS; \ 27 | if $(am__is_gnu_make); then \ 28 | sane_makeflags=$$MFLAGS; \ 29 | else \ 30 | case $$MAKEFLAGS in \ 31 | *\\[\ \ ]*) \ 32 | bs=\\; \ 33 | sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ 34 | | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ 35 | esac; \ 36 | fi; \ 37 | skip_next=no; \ 38 | strip_trailopt () \ 39 | { \ 40 | flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ 41 | }; \ 42 | for flg in $$sane_makeflags; do \ 43 | test $$skip_next = yes && { skip_next=no; continue; }; \ 44 | case $$flg in \ 45 | *=*|--*) continue;; \ 46 | -*I) strip_trailopt 'I'; skip_next=yes;; \ 47 | -*I?*) strip_trailopt 'I';; \ 48 | -*O) strip_trailopt 'O'; skip_next=yes;; \ 49 | -*O?*) strip_trailopt 'O';; \ 50 | -*l) strip_trailopt 'l'; skip_next=yes;; \ 51 | -*l?*) strip_trailopt 'l';; \ 52 | -[dEDm]) skip_next=yes;; \ 53 | -[JT]) skip_next=yes;; \ 54 | esac; \ 55 | case $$flg in \ 56 | *$$target_option*) has_opt=yes; break;; \ 57 | esac; \ 58 | done; \ 59 | test $$has_opt = yes 60 | am__make_dryrun = (target_option=n; $(am__make_running_with_option)) 61 | am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) 62 | pkgdatadir = $(datadir)/@PACKAGE@ 63 | pkgincludedir = $(includedir)/@PACKAGE@ 64 | pkglibdir = $(libdir)/@PACKAGE@ 65 | pkglibexecdir = $(libexecdir)/@PACKAGE@ 66 | am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd 67 | install_sh_DATA = $(install_sh) -c -m 644 68 | install_sh_PROGRAM = $(install_sh) -c 69 | install_sh_SCRIPT = $(install_sh) -c 70 | INSTALL_HEADER = $(INSTALL_DATA) 71 | transform = $(program_transform_name) 72 | NORMAL_INSTALL = : 73 | PRE_INSTALL = : 74 | POST_INSTALL = : 75 | NORMAL_UNINSTALL = : 76 | PRE_UNINSTALL = : 77 | POST_UNINSTALL = : 78 | subdir = . 79 | DIST_COMMON = INSTALL NEWS README AUTHORS ChangeLog \ 80 | $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ 81 | $(top_srcdir)/configure $(am__configure_deps) COPYING compile \ 82 | install-sh missing 83 | ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 84 | am__aclocal_m4_deps = $(top_srcdir)/configure.ac 85 | am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ 86 | $(ACLOCAL_M4) 87 | am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ 88 | configure.lineno config.status.lineno 89 | mkinstalldirs = $(install_sh) -d 90 | CONFIG_CLEAN_FILES = 91 | CONFIG_CLEAN_VPATH_FILES = 92 | AM_V_P = $(am__v_P_@AM_V@) 93 | am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) 94 | am__v_P_0 = false 95 | am__v_P_1 = : 96 | AM_V_GEN = $(am__v_GEN_@AM_V@) 97 | am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) 98 | am__v_GEN_0 = @echo " GEN " $@; 99 | am__v_GEN_1 = 100 | AM_V_at = $(am__v_at_@AM_V@) 101 | am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) 102 | am__v_at_0 = @ 103 | am__v_at_1 = 104 | SOURCES = 105 | DIST_SOURCES = 106 | RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ 107 | ctags-recursive dvi-recursive html-recursive info-recursive \ 108 | install-data-recursive install-dvi-recursive \ 109 | install-exec-recursive install-html-recursive \ 110 | install-info-recursive install-pdf-recursive \ 111 | install-ps-recursive install-recursive installcheck-recursive \ 112 | installdirs-recursive pdf-recursive ps-recursive \ 113 | tags-recursive uninstall-recursive 114 | am__can_run_installinfo = \ 115 | case $$AM_UPDATE_INFO_DIR in \ 116 | n|no|NO) false;; \ 117 | *) (install-info --version) >/dev/null 2>&1;; \ 118 | esac 119 | RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ 120 | distclean-recursive maintainer-clean-recursive 121 | am__recursive_targets = \ 122 | $(RECURSIVE_TARGETS) \ 123 | $(RECURSIVE_CLEAN_TARGETS) \ 124 | $(am__extra_recursive_targets) 125 | AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ 126 | cscope distdir dist dist-all distcheck 127 | am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) 128 | # Read a list of newline-separated strings from the standard input, 129 | # and print each of them once, without duplicates. Input order is 130 | # *not* preserved. 131 | am__uniquify_input = $(AWK) '\ 132 | BEGIN { nonempty = 0; } \ 133 | { items[$$0] = 1; nonempty = 1; } \ 134 | END { if (nonempty) { for (i in items) print i; }; } \ 135 | ' 136 | # Make sure the list of sources is unique. This is necessary because, 137 | # e.g., the same source file might be shared among _SOURCES variables 138 | # for different programs/libraries. 139 | am__define_uniq_tagged_files = \ 140 | list='$(am__tagged_files)'; \ 141 | unique=`for i in $$list; do \ 142 | if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ 143 | done | $(am__uniquify_input)` 144 | ETAGS = etags 145 | CTAGS = ctags 146 | CSCOPE = cscope 147 | DIST_SUBDIRS = $(SUBDIRS) 148 | DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) 149 | distdir = $(PACKAGE)-$(VERSION) 150 | top_distdir = $(distdir) 151 | am__remove_distdir = \ 152 | if test -d "$(distdir)"; then \ 153 | find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ 154 | && rm -rf "$(distdir)" \ 155 | || { sleep 5 && rm -rf "$(distdir)"; }; \ 156 | else :; fi 157 | am__post_remove_distdir = $(am__remove_distdir) 158 | am__relativize = \ 159 | dir0=`pwd`; \ 160 | sed_first='s,^\([^/]*\)/.*$$,\1,'; \ 161 | sed_rest='s,^[^/]*/*,,'; \ 162 | sed_last='s,^.*/\([^/]*\)$$,\1,'; \ 163 | sed_butlast='s,/*[^/]*$$,,'; \ 164 | while test -n "$$dir1"; do \ 165 | first=`echo "$$dir1" | sed -e "$$sed_first"`; \ 166 | if test "$$first" != "."; then \ 167 | if test "$$first" = ".."; then \ 168 | dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ 169 | dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ 170 | else \ 171 | first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ 172 | if test "$$first2" = "$$first"; then \ 173 | dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ 174 | else \ 175 | dir2="../$$dir2"; \ 176 | fi; \ 177 | dir0="$$dir0"/"$$first"; \ 178 | fi; \ 179 | fi; \ 180 | dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ 181 | done; \ 182 | reldir="$$dir2" 183 | DIST_ARCHIVES = $(distdir).tar.gz 184 | GZIP_ENV = --best 185 | DIST_TARGETS = dist-gzip 186 | distuninstallcheck_listfiles = find . -type f -print 187 | am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \ 188 | | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$' 189 | distcleancheck_listfiles = find . -type f -print 190 | ACLOCAL = @ACLOCAL@ 191 | AMTAR = @AMTAR@ 192 | AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ 193 | AUTOCONF = @AUTOCONF@ 194 | AUTOHEADER = @AUTOHEADER@ 195 | AUTOMAKE = @AUTOMAKE@ 196 | AWK = @AWK@ 197 | CC = @CC@ 198 | CCDEPMODE = @CCDEPMODE@ 199 | CFLAGS = @CFLAGS@ 200 | CPPFLAGS = @CPPFLAGS@ 201 | CXX = @CXX@ 202 | CXXCPP = @CXXCPP@ 203 | CXXDEPMODE = @CXXDEPMODE@ 204 | CXXFLAGS = @CXXFLAGS@ 205 | CYGPATH_W = @CYGPATH_W@ 206 | DEFS = @DEFS@ 207 | DEPDIR = @DEPDIR@ 208 | ECHO_C = @ECHO_C@ 209 | ECHO_N = @ECHO_N@ 210 | ECHO_T = @ECHO_T@ 211 | EGREP = @EGREP@ 212 | EXEEXT = @EXEEXT@ 213 | GREP = @GREP@ 214 | HAVE_CXX11 = @HAVE_CXX11@ 215 | INSTALL = @INSTALL@ 216 | INSTALL_DATA = @INSTALL_DATA@ 217 | INSTALL_PROGRAM = @INSTALL_PROGRAM@ 218 | INSTALL_SCRIPT = @INSTALL_SCRIPT@ 219 | INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ 220 | LDFLAGS = @LDFLAGS@ 221 | LIBOBJS = @LIBOBJS@ 222 | LIBS = @LIBS@ 223 | LTLIBOBJS = @LTLIBOBJS@ 224 | MAKEINFO = @MAKEINFO@ 225 | MKDIR_P = @MKDIR_P@ 226 | OBJEXT = @OBJEXT@ 227 | PACKAGE = @PACKAGE@ 228 | PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ 229 | PACKAGE_NAME = @PACKAGE_NAME@ 230 | PACKAGE_STRING = @PACKAGE_STRING@ 231 | PACKAGE_TARNAME = @PACKAGE_TARNAME@ 232 | PACKAGE_URL = @PACKAGE_URL@ 233 | PACKAGE_VERSION = @PACKAGE_VERSION@ 234 | PATH_SEPARATOR = @PATH_SEPARATOR@ 235 | SET_MAKE = @SET_MAKE@ 236 | SHELL = @SHELL@ 237 | STRIP = @STRIP@ 238 | VERSION = @VERSION@ 239 | abs_builddir = @abs_builddir@ 240 | abs_srcdir = @abs_srcdir@ 241 | abs_top_builddir = @abs_top_builddir@ 242 | abs_top_srcdir = @abs_top_srcdir@ 243 | ac_ct_CC = @ac_ct_CC@ 244 | ac_ct_CXX = @ac_ct_CXX@ 245 | am__include = @am__include@ 246 | am__leading_dot = @am__leading_dot@ 247 | am__quote = @am__quote@ 248 | am__tar = @am__tar@ 249 | am__untar = @am__untar@ 250 | bindir = @bindir@ 251 | build_alias = @build_alias@ 252 | builddir = @builddir@ 253 | datadir = @datadir@ 254 | datarootdir = @datarootdir@ 255 | docdir = @docdir@ 256 | dvidir = @dvidir@ 257 | exec_prefix = @exec_prefix@ 258 | host_alias = @host_alias@ 259 | htmldir = @htmldir@ 260 | includedir = @includedir@ 261 | infodir = @infodir@ 262 | install_sh = @install_sh@ 263 | libdir = @libdir@ 264 | libexecdir = @libexecdir@ 265 | localedir = @localedir@ 266 | localstatedir = @localstatedir@ 267 | mandir = @mandir@ 268 | mkdir_p = @mkdir_p@ 269 | oldincludedir = @oldincludedir@ 270 | pdfdir = @pdfdir@ 271 | prefix = @prefix@ 272 | program_transform_name = @program_transform_name@ 273 | psdir = @psdir@ 274 | sbindir = @sbindir@ 275 | sharedstatedir = @sharedstatedir@ 276 | srcdir = @srcdir@ 277 | sysconfdir = @sysconfdir@ 278 | target_alias = @target_alias@ 279 | top_build_prefix = @top_build_prefix@ 280 | top_builddir = @top_builddir@ 281 | top_srcdir = @top_srcdir@ 282 | SUBDIRS = src 283 | all: all-recursive 284 | 285 | .SUFFIXES: 286 | am--refresh: Makefile 287 | @: 288 | $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) 289 | @for dep in $?; do \ 290 | case '$(am__configure_deps)' in \ 291 | *$$dep*) \ 292 | echo ' cd $(srcdir) && $(AUTOMAKE) --gnu'; \ 293 | $(am__cd) $(srcdir) && $(AUTOMAKE) --gnu \ 294 | && exit 0; \ 295 | exit 1;; \ 296 | esac; \ 297 | done; \ 298 | echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \ 299 | $(am__cd) $(top_srcdir) && \ 300 | $(AUTOMAKE) --gnu Makefile 301 | .PRECIOUS: Makefile 302 | Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status 303 | @case '$?' in \ 304 | *config.status*) \ 305 | echo ' $(SHELL) ./config.status'; \ 306 | $(SHELL) ./config.status;; \ 307 | *) \ 308 | echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ 309 | cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ 310 | esac; 311 | 312 | $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) 313 | $(SHELL) ./config.status --recheck 314 | 315 | $(top_srcdir)/configure: $(am__configure_deps) 316 | $(am__cd) $(srcdir) && $(AUTOCONF) 317 | $(ACLOCAL_M4): $(am__aclocal_m4_deps) 318 | $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) 319 | $(am__aclocal_m4_deps): 320 | 321 | # This directory's subdirectories are mostly independent; you can cd 322 | # into them and run 'make' without going through this Makefile. 323 | # To change the values of 'make' variables: instead of editing Makefiles, 324 | # (1) if the variable is set in 'config.status', edit 'config.status' 325 | # (which will cause the Makefiles to be regenerated when you run 'make'); 326 | # (2) otherwise, pass the desired values on the 'make' command line. 327 | $(am__recursive_targets): 328 | @fail=; \ 329 | if $(am__make_keepgoing); then \ 330 | failcom='fail=yes'; \ 331 | else \ 332 | failcom='exit 1'; \ 333 | fi; \ 334 | dot_seen=no; \ 335 | target=`echo $@ | sed s/-recursive//`; \ 336 | case "$@" in \ 337 | distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ 338 | *) list='$(SUBDIRS)' ;; \ 339 | esac; \ 340 | for subdir in $$list; do \ 341 | echo "Making $$target in $$subdir"; \ 342 | if test "$$subdir" = "."; then \ 343 | dot_seen=yes; \ 344 | local_target="$$target-am"; \ 345 | else \ 346 | local_target="$$target"; \ 347 | fi; \ 348 | ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ 349 | || eval $$failcom; \ 350 | done; \ 351 | if test "$$dot_seen" = "no"; then \ 352 | $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ 353 | fi; test -z "$$fail" 354 | 355 | ID: $(am__tagged_files) 356 | $(am__define_uniq_tagged_files); mkid -fID $$unique 357 | tags: tags-recursive 358 | TAGS: tags 359 | 360 | tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) 361 | set x; \ 362 | here=`pwd`; \ 363 | if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ 364 | include_option=--etags-include; \ 365 | empty_fix=.; \ 366 | else \ 367 | include_option=--include; \ 368 | empty_fix=; \ 369 | fi; \ 370 | list='$(SUBDIRS)'; for subdir in $$list; do \ 371 | if test "$$subdir" = .; then :; else \ 372 | test ! -f $$subdir/TAGS || \ 373 | set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ 374 | fi; \ 375 | done; \ 376 | $(am__define_uniq_tagged_files); \ 377 | shift; \ 378 | if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ 379 | test -n "$$unique" || unique=$$empty_fix; \ 380 | if test $$# -gt 0; then \ 381 | $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ 382 | "$$@" $$unique; \ 383 | else \ 384 | $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ 385 | $$unique; \ 386 | fi; \ 387 | fi 388 | ctags: ctags-recursive 389 | 390 | CTAGS: ctags 391 | ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) 392 | $(am__define_uniq_tagged_files); \ 393 | test -z "$(CTAGS_ARGS)$$unique" \ 394 | || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ 395 | $$unique 396 | 397 | GTAGS: 398 | here=`$(am__cd) $(top_builddir) && pwd` \ 399 | && $(am__cd) $(top_srcdir) \ 400 | && gtags -i $(GTAGS_ARGS) "$$here" 401 | cscope: cscope.files 402 | test ! -s cscope.files \ 403 | || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS) 404 | clean-cscope: 405 | -rm -f cscope.files 406 | cscope.files: clean-cscope cscopelist 407 | cscopelist: cscopelist-recursive 408 | 409 | cscopelist-am: $(am__tagged_files) 410 | list='$(am__tagged_files)'; \ 411 | case "$(srcdir)" in \ 412 | [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ 413 | *) sdir=$(subdir)/$(srcdir) ;; \ 414 | esac; \ 415 | for i in $$list; do \ 416 | if test -f "$$i"; then \ 417 | echo "$(subdir)/$$i"; \ 418 | else \ 419 | echo "$$sdir/$$i"; \ 420 | fi; \ 421 | done >> $(top_builddir)/cscope.files 422 | 423 | distclean-tags: 424 | -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags 425 | -rm -f cscope.out cscope.in.out cscope.po.out cscope.files 426 | 427 | distdir: $(DISTFILES) 428 | $(am__remove_distdir) 429 | test -d "$(distdir)" || mkdir "$(distdir)" 430 | @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ 431 | topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ 432 | list='$(DISTFILES)'; \ 433 | dist_files=`for file in $$list; do echo $$file; done | \ 434 | sed -e "s|^$$srcdirstrip/||;t" \ 435 | -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ 436 | case $$dist_files in \ 437 | */*) $(MKDIR_P) `echo "$$dist_files" | \ 438 | sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ 439 | sort -u` ;; \ 440 | esac; \ 441 | for file in $$dist_files; do \ 442 | if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ 443 | if test -d $$d/$$file; then \ 444 | dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ 445 | if test -d "$(distdir)/$$file"; then \ 446 | find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ 447 | fi; \ 448 | if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ 449 | cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ 450 | find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ 451 | fi; \ 452 | cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ 453 | else \ 454 | test -f "$(distdir)/$$file" \ 455 | || cp -p $$d/$$file "$(distdir)/$$file" \ 456 | || exit 1; \ 457 | fi; \ 458 | done 459 | @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ 460 | if test "$$subdir" = .; then :; else \ 461 | $(am__make_dryrun) \ 462 | || test -d "$(distdir)/$$subdir" \ 463 | || $(MKDIR_P) "$(distdir)/$$subdir" \ 464 | || exit 1; \ 465 | dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ 466 | $(am__relativize); \ 467 | new_distdir=$$reldir; \ 468 | dir1=$$subdir; dir2="$(top_distdir)"; \ 469 | $(am__relativize); \ 470 | new_top_distdir=$$reldir; \ 471 | echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ 472 | echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ 473 | ($(am__cd) $$subdir && \ 474 | $(MAKE) $(AM_MAKEFLAGS) \ 475 | top_distdir="$$new_top_distdir" \ 476 | distdir="$$new_distdir" \ 477 | am__remove_distdir=: \ 478 | am__skip_length_check=: \ 479 | am__skip_mode_fix=: \ 480 | distdir) \ 481 | || exit 1; \ 482 | fi; \ 483 | done 484 | -test -n "$(am__skip_mode_fix)" \ 485 | || find "$(distdir)" -type d ! -perm -755 \ 486 | -exec chmod u+rwx,go+rx {} \; -o \ 487 | ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ 488 | ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ 489 | ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ 490 | || chmod -R a+r "$(distdir)" 491 | dist-gzip: distdir 492 | tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz 493 | $(am__post_remove_distdir) 494 | 495 | dist-bzip2: distdir 496 | tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2 497 | $(am__post_remove_distdir) 498 | 499 | dist-lzip: distdir 500 | tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz 501 | $(am__post_remove_distdir) 502 | 503 | dist-xz: distdir 504 | tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz 505 | $(am__post_remove_distdir) 506 | 507 | dist-tarZ: distdir 508 | @echo WARNING: "Support for shar distribution archives is" \ 509 | "deprecated." >&2 510 | @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 511 | tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z 512 | $(am__post_remove_distdir) 513 | 514 | dist-shar: distdir 515 | @echo WARNING: "Support for distribution archives compressed with" \ 516 | "legacy program 'compress' is deprecated." >&2 517 | @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 518 | shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz 519 | $(am__post_remove_distdir) 520 | 521 | dist-zip: distdir 522 | -rm -f $(distdir).zip 523 | zip -rq $(distdir).zip $(distdir) 524 | $(am__post_remove_distdir) 525 | 526 | dist dist-all: 527 | $(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:' 528 | $(am__post_remove_distdir) 529 | 530 | # This target untars the dist file and tries a VPATH configuration. Then 531 | # it guarantees that the distribution is self-contained by making another 532 | # tarfile. 533 | distcheck: dist 534 | case '$(DIST_ARCHIVES)' in \ 535 | *.tar.gz*) \ 536 | GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\ 537 | *.tar.bz2*) \ 538 | bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ 539 | *.tar.lz*) \ 540 | lzip -dc $(distdir).tar.lz | $(am__untar) ;;\ 541 | *.tar.xz*) \ 542 | xz -dc $(distdir).tar.xz | $(am__untar) ;;\ 543 | *.tar.Z*) \ 544 | uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ 545 | *.shar.gz*) \ 546 | GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\ 547 | *.zip*) \ 548 | unzip $(distdir).zip ;;\ 549 | esac 550 | chmod -R a-w $(distdir) 551 | chmod u+w $(distdir) 552 | mkdir $(distdir)/_build $(distdir)/_inst 553 | chmod a-w $(distdir) 554 | test -d $(distdir)/_build || exit 0; \ 555 | dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ 556 | && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ 557 | && am__cwd=`pwd` \ 558 | && $(am__cd) $(distdir)/_build \ 559 | && ../configure \ 560 | $(AM_DISTCHECK_CONFIGURE_FLAGS) \ 561 | $(DISTCHECK_CONFIGURE_FLAGS) \ 562 | --srcdir=.. --prefix="$$dc_install_base" \ 563 | && $(MAKE) $(AM_MAKEFLAGS) \ 564 | && $(MAKE) $(AM_MAKEFLAGS) dvi \ 565 | && $(MAKE) $(AM_MAKEFLAGS) check \ 566 | && $(MAKE) $(AM_MAKEFLAGS) install \ 567 | && $(MAKE) $(AM_MAKEFLAGS) installcheck \ 568 | && $(MAKE) $(AM_MAKEFLAGS) uninstall \ 569 | && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ 570 | distuninstallcheck \ 571 | && chmod -R a-w "$$dc_install_base" \ 572 | && ({ \ 573 | (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ 574 | && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ 575 | && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ 576 | && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ 577 | distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ 578 | } || { rm -rf "$$dc_destdir"; exit 1; }) \ 579 | && rm -rf "$$dc_destdir" \ 580 | && $(MAKE) $(AM_MAKEFLAGS) dist \ 581 | && rm -rf $(DIST_ARCHIVES) \ 582 | && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ 583 | && cd "$$am__cwd" \ 584 | || exit 1 585 | $(am__post_remove_distdir) 586 | @(echo "$(distdir) archives ready for distribution: "; \ 587 | list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ 588 | sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' 589 | distuninstallcheck: 590 | @test -n '$(distuninstallcheck_dir)' || { \ 591 | echo 'ERROR: trying to run $@ with an empty' \ 592 | '$$(distuninstallcheck_dir)' >&2; \ 593 | exit 1; \ 594 | }; \ 595 | $(am__cd) '$(distuninstallcheck_dir)' || { \ 596 | echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \ 597 | exit 1; \ 598 | }; \ 599 | test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \ 600 | || { echo "ERROR: files left after uninstall:" ; \ 601 | if test -n "$(DESTDIR)"; then \ 602 | echo " (check DESTDIR support)"; \ 603 | fi ; \ 604 | $(distuninstallcheck_listfiles) ; \ 605 | exit 1; } >&2 606 | distcleancheck: distclean 607 | @if test '$(srcdir)' = . ; then \ 608 | echo "ERROR: distcleancheck can only run from a VPATH build" ; \ 609 | exit 1 ; \ 610 | fi 611 | @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ 612 | || { echo "ERROR: files left in build directory after distclean:" ; \ 613 | $(distcleancheck_listfiles) ; \ 614 | exit 1; } >&2 615 | check-am: all-am 616 | check: check-recursive 617 | all-am: Makefile 618 | installdirs: installdirs-recursive 619 | installdirs-am: 620 | install: install-recursive 621 | install-exec: install-exec-recursive 622 | install-data: install-data-recursive 623 | uninstall: uninstall-recursive 624 | 625 | install-am: all-am 626 | @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am 627 | 628 | installcheck: installcheck-recursive 629 | install-strip: 630 | if test -z '$(STRIP)'; then \ 631 | $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ 632 | install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ 633 | install; \ 634 | else \ 635 | $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ 636 | install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ 637 | "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ 638 | fi 639 | mostlyclean-generic: 640 | 641 | clean-generic: 642 | 643 | distclean-generic: 644 | -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) 645 | -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) 646 | 647 | maintainer-clean-generic: 648 | @echo "This command is intended for maintainers to use" 649 | @echo "it deletes files that may require special tools to rebuild." 650 | clean: clean-recursive 651 | 652 | clean-am: clean-generic mostlyclean-am 653 | 654 | distclean: distclean-recursive 655 | -rm -f $(am__CONFIG_DISTCLEAN_FILES) 656 | -rm -f Makefile 657 | distclean-am: clean-am distclean-generic distclean-tags 658 | 659 | dvi: dvi-recursive 660 | 661 | dvi-am: 662 | 663 | html: html-recursive 664 | 665 | html-am: 666 | 667 | info: info-recursive 668 | 669 | info-am: 670 | 671 | install-data-am: 672 | 673 | install-dvi: install-dvi-recursive 674 | 675 | install-dvi-am: 676 | 677 | install-exec-am: 678 | 679 | install-html: install-html-recursive 680 | 681 | install-html-am: 682 | 683 | install-info: install-info-recursive 684 | 685 | install-info-am: 686 | 687 | install-man: 688 | 689 | install-pdf: install-pdf-recursive 690 | 691 | install-pdf-am: 692 | 693 | install-ps: install-ps-recursive 694 | 695 | install-ps-am: 696 | 697 | installcheck-am: 698 | 699 | maintainer-clean: maintainer-clean-recursive 700 | -rm -f $(am__CONFIG_DISTCLEAN_FILES) 701 | -rm -rf $(top_srcdir)/autom4te.cache 702 | -rm -f Makefile 703 | maintainer-clean-am: distclean-am maintainer-clean-generic 704 | 705 | mostlyclean: mostlyclean-recursive 706 | 707 | mostlyclean-am: mostlyclean-generic 708 | 709 | pdf: pdf-recursive 710 | 711 | pdf-am: 712 | 713 | ps: ps-recursive 714 | 715 | ps-am: 716 | 717 | uninstall-am: 718 | 719 | .MAKE: $(am__recursive_targets) install-am install-strip 720 | 721 | .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \ 722 | am--refresh check check-am clean clean-cscope clean-generic \ 723 | cscope cscopelist-am ctags ctags-am dist dist-all dist-bzip2 \ 724 | dist-gzip dist-lzip dist-shar dist-tarZ dist-xz dist-zip \ 725 | distcheck distclean distclean-generic distclean-tags \ 726 | distcleancheck distdir distuninstallcheck dvi dvi-am html \ 727 | html-am info info-am install install-am install-data \ 728 | install-data-am install-dvi install-dvi-am install-exec \ 729 | install-exec-am install-html install-html-am install-info \ 730 | install-info-am install-man install-pdf install-pdf-am \ 731 | install-ps install-ps-am install-strip installcheck \ 732 | installcheck-am installdirs installdirs-am maintainer-clean \ 733 | maintainer-clean-generic mostlyclean mostlyclean-generic pdf \ 734 | pdf-am ps ps-am tags tags-am uninstall uninstall-am 735 | 736 | 737 | # Tell versions [3.59,3.63) of GNU make to not export all variables. 738 | # Otherwise a system limit (for SysV at least) may be exceeded. 739 | .NOEXPORT: 740 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- 1 | Version 0.1 released on April 2, 2013 2 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Please check out README.md 2 | 3 | https://github.com/pekingduck/metadsf 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | metadsf 2 | ======= 3 | `metadsf` is a command line tool that lets you batch-edit ID3v2 tags embedded in your DSF files. 4 | 5 | ``` sh 6 | # long options 7 | $ metadsf --set-tag=TPE1=Eagles --set-tag=TIT2="Hotel California" music.dsf 8 | $ metadsf --show-tags music.dsf 9 | TPE1=Eagles 10 | TIT2=Hotel California 11 | 12 | # short options 13 | $ metadsf -sTPE1='Pink Floyd' -sTIT2=Money music.dsf 14 | ``` 15 | 16 | Installation 17 | ------------ 18 | Dependencies: 19 | * **taglib 1.9.1** or newer 20 | * A C++11-compliant compiler 21 | 22 | ```sh 23 | # You may have to tell configure where your taglib is located 24 | $ ./configure --prefix=/usr/local/ 25 | $ make 26 | $ make install 27 | ``` 28 | 29 | Options 30 | ------- 31 | Usage: metadsf [options] file1 file2 file3 ... 32 | 33 | #### `--help` or `-h` 34 | Display help info and exit. 35 | 36 | #### `--version` or `-v` 37 | Display the current version of `metadsf` and exit. 38 | 39 | #### `--show-info` or `-i` 40 | Display audio properties of the specified DSF files. 41 | If more than one file are specified in the command line, each output line will be preceded by 42 | the corresponding file name. 43 | 44 | #### `--show-tags` or `-t` 45 | Display all ID3v2 tags in the specified DSF files. 46 | If more than one file are specified in the command line, each output line will be preceded by 47 | the file name. 48 | 49 | #### `--encoding` or `-e` 50 | Set the text encoding of your input to various commands. Valid encodings are: "UTF8" (default), "LATIN1", "UTF16", "UTF16LE", "UTF16BE". 51 | 52 | ```sh 53 | $ metadsf --set-tag=TALB="My Album" --encoding=UTF8 mymusic.dsf 54 | $ metadsf --set-tag=TALB="My Album" -eUTF8 55 | ``` 56 | 57 | #### `--id3v2-version` 58 | Save ID3v2 tags in either 2.3.0 or 2.4.0 version. Can be either 3 or 4. 59 | ```sh 60 | # Save as ID3v2 2.3.0 61 | $ metadsf -sTPE1=XXX --id3v2-version=3 62 | ``` 63 | 64 | #### `--add-tag` or `-a` 65 | Add a tag. Existing tags with the same name are untouched. 66 | ```sh 67 | $ metadsf --add-tag=TRCK=4 -aTPOS=1/2 test.dsf 68 | ``` 69 | 70 | #### `--add-tags-from-file` 71 | Same as `--add-tag`, but instead of specify the key-value pairs in the command line, you can supply a text file containing the pairs (one per line). 72 | ```sh 73 | $ cat tags.txt 74 | TPE1=Rolling Stones 75 | TPOS=1/1 76 | $ metadsf --add-tags-from-file=tags.txt test.dsf 77 | ``` 78 | 79 | #### `--set-tag` or `-s` 80 | This **replaces** all occurences of the tag with the specified value. 81 | ```sh 82 | $ metadsf --show-tags test.dsf 83 | TPE2=XYZ 84 | TPE2=ABC 85 | # replace and display tags 86 | $ metadsf --set-tag=TPE=IJK --show-tags test.dsf 87 | TPE2=IJK 88 | ``` 89 | 90 | #### `--set-tags-from-file` 91 | Same as `--set-tag`, but instead of specify the key-value pairs in the command line, you can supply a text file containing the pairs (one per line). 92 | 93 | #### `--import-picture` or `-p` 94 | Import picture into the DSF file 95 | ```sh 96 | # long form 97 | $ metadsf --import-picture='/path/to/your.jpg|3|Picture Comment' test.dsf 98 | # short form 99 | $ metadsf -p'/some/dir/file.jpg' 100 | ``` 101 | 102 | The string is a list of fields separated by '|'. The first field is the path to your picture file. 103 | The second field is the picture type which is optional (the default is "3" which means "Front Cover") 104 | The third field is picture comment which is also optional. 105 | ```sh 106 | $ metadsf --import-picture='/path/to/your.jpg' 107 | # no comment specified 108 | $ metadsf --import-picture='/path/to/your.jpg|11' 109 | # no picture type specified 110 | $ metadsf --import-picture='/path/to/your.jpg||My Comment' 111 | ``` 112 | 113 | Currently GIF(`.gif`), TIFF (`.tif` or `.tiff`), PNG(`.png`) and JPEG(`.jpeg`, `.jpg`, `.jpe`) files are allowed. 114 | 115 | See Appendix I for the complete list of picture types. 116 | 117 | #### `--export-all-pictures` 118 | Export embedded pictures to files. Exported files are named `__.`. 119 | 120 | E.g. let's say you have 2 front covers and 1 back cover in JPEG format embedded inside `SomeDSDFile.dsf`: 121 | ```sh 122 | $ metadsf --export-all-pictures SomeDSDFile.dsf 123 | $ ls *.jpg 124 | SomeDSDFile_FrontCover_1.jpg 125 | SomeDSDFile_FrontCover_2.jpg 126 | SomeDSDFile_BackCover_1.jpg 127 | ``` 128 | 129 | #### `--remove-tags` or `-r` 130 | A comma-separated list of tag names to be removed. 131 | ```sh 132 | $ metadsf --remove-tags=TPE1,TPE2 133 | ``` 134 | 135 | #### `--remove-pictures` 136 | A comma-separated list of picture types to be removed. 137 | ```sh 138 | # remove ALL front and back covers 139 | $ metadsf --remove-pictures=3,4 140 | ``` 141 | 142 | #### `--remove-all-pictures` 143 | Remove all embedded pictures in the file 144 | 145 | #### `--remove-everything` 146 | Remove **ALL** ID3v2 metadata including tags and pictures. 147 | 148 | Examples 149 | -------- 150 | Note that you can mix and match options together 151 | ```sh 152 | # Clear everything and start all over again 153 | $ metadsf --remove-everything -sTALB=Thriller --import-picture=thriller.jpg 01-Beat_It.dsf 02-Thriller.dsf 154 | 155 | # Remove all pictures and a couple tags, and import new pictures 156 | $ metadsf --remove-all-pictures -rTALB,WCOP --import-picture=somepic.jpg --import-picture=anotherpic.jpg music.dsf 157 | ``` 158 | 159 | TODO 160 | ---- 161 | 1. Support for TXXX, WXXX, TMCP, TIPL tags 162 | 163 | 164 | Appendix I 165 | ---------- 166 | Below is the complete list of picture types. 167 | * 0: Other 168 | * 1: 32x32 pixels 'file icon' 169 | * 2: Other file icon 170 | * 3: Cover (front) 171 | * 4: Cover (back) 172 | * 5: Leaflet page 173 | * 6: Media (e.g. label side of CD) 174 | * 7: Lead artist/lead performer/soloist 175 | * 8: Artist/performer 176 | * 9: Conductor 177 | * 10: Band/Orchestra 178 | * 11: Composer 179 | * 12: Lyricist/text writer 180 | * 13: Recording Location 181 | * 14: During recording 182 | * 15: During performance 183 | * 16: Movie/video screen capture 184 | * 17: A bright coloured fish 185 | * 18: Illustration 186 | * 19: Band/artist logotype 187 | * 20: Publisher/Studio logotype 188 | 189 | Appendix II 190 | ----------- 191 | Below is the complete list of supported ID3v2 tags 192 | * TALB 193 | * TBPM 194 | * TCOM 195 | * TCON 196 | * TCOP 197 | * TDEN 198 | * TDLY 199 | * TDOR 200 | * TDRC 201 | * TDRL 202 | * TDTG 203 | * TENC 204 | * TEXT 205 | * TFLT 206 | * TIT1 207 | * TIT2 208 | * TIT3 209 | * TKEY 210 | * TLAN 211 | * TLEN 212 | * TMED 213 | * TMOO 214 | * TOAL 215 | * TOFN 216 | * TOLY 217 | * TOPE 218 | * TOWN 219 | * TPE1 220 | * TPE2 221 | * TPE3 222 | * TPE4 223 | * TPOS 224 | * TPRO 225 | * TPUB 226 | * TRCK 227 | * TRSN 228 | * TRSO 229 | * TSOA 230 | * TSOP 231 | * TSOT 232 | * TSO2 233 | * TSRC 234 | * TSSE 235 | * WCOP 236 | * WOAF 237 | * WOAR 238 | * WOAS 239 | * WORS 240 | * WPAY 241 | * WPUB 242 | * COMM 243 | * TRDA 244 | * TDAT 245 | * TYER 246 | * TIME 247 | -------------------------------------------------------------------------------- /compile: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # Wrapper for compilers which do not understand '-c -o'. 3 | 4 | scriptversion=2012-10-14.11; # UTC 5 | 6 | # Copyright (C) 1999-2013 Free Software Foundation, Inc. 7 | # Written by Tom Tromey . 8 | # 9 | # This program is free software; you can redistribute it and/or modify 10 | # it under the terms of the GNU General Public License as published by 11 | # the Free Software Foundation; either version 2, or (at your option) 12 | # any later version. 13 | # 14 | # This program is distributed in the hope that it will be useful, 15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | # GNU General Public License for more details. 18 | # 19 | # You should have received a copy of the GNU General Public License 20 | # along with this program. If not, see . 21 | 22 | # As a special exception to the GNU General Public License, if you 23 | # distribute this file as part of a program that contains a 24 | # configuration script generated by Autoconf, you may include it under 25 | # the same distribution terms that you use for the rest of that program. 26 | 27 | # This file is maintained in Automake, please report 28 | # bugs to or send patches to 29 | # . 30 | 31 | nl=' 32 | ' 33 | 34 | # We need space, tab and new line, in precisely that order. Quoting is 35 | # there to prevent tools from complaining about whitespace usage. 36 | IFS=" "" $nl" 37 | 38 | file_conv= 39 | 40 | # func_file_conv build_file lazy 41 | # Convert a $build file to $host form and store it in $file 42 | # Currently only supports Windows hosts. If the determined conversion 43 | # type is listed in (the comma separated) LAZY, no conversion will 44 | # take place. 45 | func_file_conv () 46 | { 47 | file=$1 48 | case $file in 49 | / | /[!/]*) # absolute file, and not a UNC file 50 | if test -z "$file_conv"; then 51 | # lazily determine how to convert abs files 52 | case `uname -s` in 53 | MINGW*) 54 | file_conv=mingw 55 | ;; 56 | CYGWIN*) 57 | file_conv=cygwin 58 | ;; 59 | *) 60 | file_conv=wine 61 | ;; 62 | esac 63 | fi 64 | case $file_conv/,$2, in 65 | *,$file_conv,*) 66 | ;; 67 | mingw/*) 68 | file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` 69 | ;; 70 | cygwin/*) 71 | file=`cygpath -m "$file" || echo "$file"` 72 | ;; 73 | wine/*) 74 | file=`winepath -w "$file" || echo "$file"` 75 | ;; 76 | esac 77 | ;; 78 | esac 79 | } 80 | 81 | # func_cl_dashL linkdir 82 | # Make cl look for libraries in LINKDIR 83 | func_cl_dashL () 84 | { 85 | func_file_conv "$1" 86 | if test -z "$lib_path"; then 87 | lib_path=$file 88 | else 89 | lib_path="$lib_path;$file" 90 | fi 91 | linker_opts="$linker_opts -LIBPATH:$file" 92 | } 93 | 94 | # func_cl_dashl library 95 | # Do a library search-path lookup for cl 96 | func_cl_dashl () 97 | { 98 | lib=$1 99 | found=no 100 | save_IFS=$IFS 101 | IFS=';' 102 | for dir in $lib_path $LIB 103 | do 104 | IFS=$save_IFS 105 | if $shared && test -f "$dir/$lib.dll.lib"; then 106 | found=yes 107 | lib=$dir/$lib.dll.lib 108 | break 109 | fi 110 | if test -f "$dir/$lib.lib"; then 111 | found=yes 112 | lib=$dir/$lib.lib 113 | break 114 | fi 115 | if test -f "$dir/lib$lib.a"; then 116 | found=yes 117 | lib=$dir/lib$lib.a 118 | break 119 | fi 120 | done 121 | IFS=$save_IFS 122 | 123 | if test "$found" != yes; then 124 | lib=$lib.lib 125 | fi 126 | } 127 | 128 | # func_cl_wrapper cl arg... 129 | # Adjust compile command to suit cl 130 | func_cl_wrapper () 131 | { 132 | # Assume a capable shell 133 | lib_path= 134 | shared=: 135 | linker_opts= 136 | for arg 137 | do 138 | if test -n "$eat"; then 139 | eat= 140 | else 141 | case $1 in 142 | -o) 143 | # configure might choose to run compile as 'compile cc -o foo foo.c'. 144 | eat=1 145 | case $2 in 146 | *.o | *.[oO][bB][jJ]) 147 | func_file_conv "$2" 148 | set x "$@" -Fo"$file" 149 | shift 150 | ;; 151 | *) 152 | func_file_conv "$2" 153 | set x "$@" -Fe"$file" 154 | shift 155 | ;; 156 | esac 157 | ;; 158 | -I) 159 | eat=1 160 | func_file_conv "$2" mingw 161 | set x "$@" -I"$file" 162 | shift 163 | ;; 164 | -I*) 165 | func_file_conv "${1#-I}" mingw 166 | set x "$@" -I"$file" 167 | shift 168 | ;; 169 | -l) 170 | eat=1 171 | func_cl_dashl "$2" 172 | set x "$@" "$lib" 173 | shift 174 | ;; 175 | -l*) 176 | func_cl_dashl "${1#-l}" 177 | set x "$@" "$lib" 178 | shift 179 | ;; 180 | -L) 181 | eat=1 182 | func_cl_dashL "$2" 183 | ;; 184 | -L*) 185 | func_cl_dashL "${1#-L}" 186 | ;; 187 | -static) 188 | shared=false 189 | ;; 190 | -Wl,*) 191 | arg=${1#-Wl,} 192 | save_ifs="$IFS"; IFS=',' 193 | for flag in $arg; do 194 | IFS="$save_ifs" 195 | linker_opts="$linker_opts $flag" 196 | done 197 | IFS="$save_ifs" 198 | ;; 199 | -Xlinker) 200 | eat=1 201 | linker_opts="$linker_opts $2" 202 | ;; 203 | -*) 204 | set x "$@" "$1" 205 | shift 206 | ;; 207 | *.cc | *.CC | *.cxx | *.CXX | *.[cC]++) 208 | func_file_conv "$1" 209 | set x "$@" -Tp"$file" 210 | shift 211 | ;; 212 | *.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO]) 213 | func_file_conv "$1" mingw 214 | set x "$@" "$file" 215 | shift 216 | ;; 217 | *) 218 | set x "$@" "$1" 219 | shift 220 | ;; 221 | esac 222 | fi 223 | shift 224 | done 225 | if test -n "$linker_opts"; then 226 | linker_opts="-link$linker_opts" 227 | fi 228 | exec "$@" $linker_opts 229 | exit 1 230 | } 231 | 232 | eat= 233 | 234 | case $1 in 235 | '') 236 | echo "$0: No command. Try '$0 --help' for more information." 1>&2 237 | exit 1; 238 | ;; 239 | -h | --h*) 240 | cat <<\EOF 241 | Usage: compile [--help] [--version] PROGRAM [ARGS] 242 | 243 | Wrapper for compilers which do not understand '-c -o'. 244 | Remove '-o dest.o' from ARGS, run PROGRAM with the remaining 245 | arguments, and rename the output as expected. 246 | 247 | If you are trying to build a whole package this is not the 248 | right script to run: please start by reading the file 'INSTALL'. 249 | 250 | Report bugs to . 251 | EOF 252 | exit $? 253 | ;; 254 | -v | --v*) 255 | echo "compile $scriptversion" 256 | exit $? 257 | ;; 258 | cl | *[/\\]cl | cl.exe | *[/\\]cl.exe ) 259 | func_cl_wrapper "$@" # Doesn't return... 260 | ;; 261 | esac 262 | 263 | ofile= 264 | cfile= 265 | 266 | for arg 267 | do 268 | if test -n "$eat"; then 269 | eat= 270 | else 271 | case $1 in 272 | -o) 273 | # configure might choose to run compile as 'compile cc -o foo foo.c'. 274 | # So we strip '-o arg' only if arg is an object. 275 | eat=1 276 | case $2 in 277 | *.o | *.obj) 278 | ofile=$2 279 | ;; 280 | *) 281 | set x "$@" -o "$2" 282 | shift 283 | ;; 284 | esac 285 | ;; 286 | *.c) 287 | cfile=$1 288 | set x "$@" "$1" 289 | shift 290 | ;; 291 | *) 292 | set x "$@" "$1" 293 | shift 294 | ;; 295 | esac 296 | fi 297 | shift 298 | done 299 | 300 | if test -z "$ofile" || test -z "$cfile"; then 301 | # If no '-o' option was seen then we might have been invoked from a 302 | # pattern rule where we don't need one. That is ok -- this is a 303 | # normal compilation that the losing compiler can handle. If no 304 | # '.c' file was seen then we are probably linking. That is also 305 | # ok. 306 | exec "$@" 307 | fi 308 | 309 | # Name of file we expect compiler to create. 310 | cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'` 311 | 312 | # Create the lock directory. 313 | # Note: use '[/\\:.-]' here to ensure that we don't use the same name 314 | # that we are using for the .o file. Also, base the name on the expected 315 | # object file name, since that is what matters with a parallel build. 316 | lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d 317 | while true; do 318 | if mkdir "$lockdir" >/dev/null 2>&1; then 319 | break 320 | fi 321 | sleep 1 322 | done 323 | # FIXME: race condition here if user kills between mkdir and trap. 324 | trap "rmdir '$lockdir'; exit 1" 1 2 15 325 | 326 | # Run the compile. 327 | "$@" 328 | ret=$? 329 | 330 | if test -f "$cofile"; then 331 | test "$cofile" = "$ofile" || mv "$cofile" "$ofile" 332 | elif test -f "${cofile}bj"; then 333 | test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile" 334 | fi 335 | 336 | rmdir "$lockdir" 337 | exit $ret 338 | 339 | # Local Variables: 340 | # mode: shell-script 341 | # sh-indentation: 2 342 | # eval: (add-hook 'write-file-hooks 'time-stamp) 343 | # time-stamp-start: "scriptversion=" 344 | # time-stamp-format: "%:y-%02m-%02d.%02H" 345 | # time-stamp-time-zone: "UTC" 346 | # time-stamp-end: "; # UTC" 347 | # End: 348 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | # -*- Autoconf -*- 2 | # Process this file with autoconf to produce a configure script. 3 | AC_CONFIG_MACRO_DIR([m4]) 4 | AC_PREREQ([2.69]) 5 | AC_INIT([metadsf], [0.1], [pekingducklabs@gmail.com]) 6 | AC_CONFIG_SRCDIR([src/main.cpp]) 7 | #AC_CONFIG_HEADERS([config.h]) 8 | AM_INIT_AUTOMAKE 9 | 10 | # Checks for programs. 11 | AC_PROG_CXX 12 | AC_PROG_CC 13 | 14 | AC_LANG(C++) 15 | # Checks for libraries. 16 | # taglib checks 17 | SAVED_LIBS=$LIBS 18 | LIBS="$LIBS -ltag -lz" 19 | AC_LINK_IFELSE( 20 | [AC_LANG_PROGRAM([#include ], 21 | [TagLib::String dummy])], 22 | [TEST_LIBS="$TEST_LIBS -ltag -lz"] [HAVE_TAGLIB=1], 23 | [AC_MSG_FAILURE([TagLib is not installed.])]) 24 | LIBS=$SAVED_LIBS 25 | # c++11 check 26 | AX_CXX_COMPILE_STDCXX_11([noext],[mandatory]) 27 | # zlib check 28 | AC_CHECK_LIB([z], [gzwrite]) 29 | 30 | # Checks for header files. 31 | AC_CHECK_HEADERS([string.h]) 32 | 33 | # Checks for typedefs, structures, and compiler characteristics. 34 | AC_CHECK_HEADER_STDBOOL 35 | AC_C_INLINE 36 | AC_TYPE_SIZE_T 37 | AC_TYPE_UINT32_T 38 | AC_TYPE_UINT64_T 39 | 40 | # Checks for library functions. 41 | AC_FUNC_ERROR_AT_LINE 42 | AC_CHECK_FUNCS([memset]) 43 | 44 | AC_CONFIG_FILES([Makefile src/Makefile]) 45 | AC_OUTPUT 46 | -------------------------------------------------------------------------------- /install-sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # install - install a program, script, or datafile 3 | 4 | scriptversion=2011-11-20.07; # UTC 5 | 6 | # This originates from X11R5 (mit/util/scripts/install.sh), which was 7 | # later released in X11R6 (xc/config/util/install.sh) with the 8 | # following copyright and license. 9 | # 10 | # Copyright (C) 1994 X Consortium 11 | # 12 | # Permission is hereby granted, free of charge, to any person obtaining a copy 13 | # of this software and associated documentation files (the "Software"), to 14 | # deal in the Software without restriction, including without limitation the 15 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 16 | # sell copies of the Software, and to permit persons to whom the Software is 17 | # furnished to do so, subject to the following conditions: 18 | # 19 | # The above copyright notice and this permission notice shall be included in 20 | # all copies or substantial portions of the Software. 21 | # 22 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 26 | # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- 27 | # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28 | # 29 | # Except as contained in this notice, the name of the X Consortium shall not 30 | # be used in advertising or otherwise to promote the sale, use or other deal- 31 | # ings in this Software without prior written authorization from the X Consor- 32 | # tium. 33 | # 34 | # 35 | # FSF changes to this file are in the public domain. 36 | # 37 | # Calling this script install-sh is preferred over install.sh, to prevent 38 | # 'make' implicit rules from creating a file called install from it 39 | # when there is no Makefile. 40 | # 41 | # This script is compatible with the BSD install script, but was written 42 | # from scratch. 43 | 44 | nl=' 45 | ' 46 | IFS=" "" $nl" 47 | 48 | # set DOITPROG to echo to test this script 49 | 50 | # Don't use :- since 4.3BSD and earlier shells don't like it. 51 | doit=${DOITPROG-} 52 | if test -z "$doit"; then 53 | doit_exec=exec 54 | else 55 | doit_exec=$doit 56 | fi 57 | 58 | # Put in absolute file names if you don't have them in your path; 59 | # or use environment vars. 60 | 61 | chgrpprog=${CHGRPPROG-chgrp} 62 | chmodprog=${CHMODPROG-chmod} 63 | chownprog=${CHOWNPROG-chown} 64 | cmpprog=${CMPPROG-cmp} 65 | cpprog=${CPPROG-cp} 66 | mkdirprog=${MKDIRPROG-mkdir} 67 | mvprog=${MVPROG-mv} 68 | rmprog=${RMPROG-rm} 69 | stripprog=${STRIPPROG-strip} 70 | 71 | posix_glob='?' 72 | initialize_posix_glob=' 73 | test "$posix_glob" != "?" || { 74 | if (set -f) 2>/dev/null; then 75 | posix_glob= 76 | else 77 | posix_glob=: 78 | fi 79 | } 80 | ' 81 | 82 | posix_mkdir= 83 | 84 | # Desired mode of installed file. 85 | mode=0755 86 | 87 | chgrpcmd= 88 | chmodcmd=$chmodprog 89 | chowncmd= 90 | mvcmd=$mvprog 91 | rmcmd="$rmprog -f" 92 | stripcmd= 93 | 94 | src= 95 | dst= 96 | dir_arg= 97 | dst_arg= 98 | 99 | copy_on_change=false 100 | no_target_directory= 101 | 102 | usage="\ 103 | Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE 104 | or: $0 [OPTION]... SRCFILES... DIRECTORY 105 | or: $0 [OPTION]... -t DIRECTORY SRCFILES... 106 | or: $0 [OPTION]... -d DIRECTORIES... 107 | 108 | In the 1st form, copy SRCFILE to DSTFILE. 109 | In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. 110 | In the 4th, create DIRECTORIES. 111 | 112 | Options: 113 | --help display this help and exit. 114 | --version display version info and exit. 115 | 116 | -c (ignored) 117 | -C install only if different (preserve the last data modification time) 118 | -d create directories instead of installing files. 119 | -g GROUP $chgrpprog installed files to GROUP. 120 | -m MODE $chmodprog installed files to MODE. 121 | -o USER $chownprog installed files to USER. 122 | -s $stripprog installed files. 123 | -t DIRECTORY install into DIRECTORY. 124 | -T report an error if DSTFILE is a directory. 125 | 126 | Environment variables override the default commands: 127 | CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG 128 | RMPROG STRIPPROG 129 | " 130 | 131 | while test $# -ne 0; do 132 | case $1 in 133 | -c) ;; 134 | 135 | -C) copy_on_change=true;; 136 | 137 | -d) dir_arg=true;; 138 | 139 | -g) chgrpcmd="$chgrpprog $2" 140 | shift;; 141 | 142 | --help) echo "$usage"; exit $?;; 143 | 144 | -m) mode=$2 145 | case $mode in 146 | *' '* | *' '* | *' 147 | '* | *'*'* | *'?'* | *'['*) 148 | echo "$0: invalid mode: $mode" >&2 149 | exit 1;; 150 | esac 151 | shift;; 152 | 153 | -o) chowncmd="$chownprog $2" 154 | shift;; 155 | 156 | -s) stripcmd=$stripprog;; 157 | 158 | -t) dst_arg=$2 159 | # Protect names problematic for 'test' and other utilities. 160 | case $dst_arg in 161 | -* | [=\(\)!]) dst_arg=./$dst_arg;; 162 | esac 163 | shift;; 164 | 165 | -T) no_target_directory=true;; 166 | 167 | --version) echo "$0 $scriptversion"; exit $?;; 168 | 169 | --) shift 170 | break;; 171 | 172 | -*) echo "$0: invalid option: $1" >&2 173 | exit 1;; 174 | 175 | *) break;; 176 | esac 177 | shift 178 | done 179 | 180 | if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then 181 | # When -d is used, all remaining arguments are directories to create. 182 | # When -t is used, the destination is already specified. 183 | # Otherwise, the last argument is the destination. Remove it from $@. 184 | for arg 185 | do 186 | if test -n "$dst_arg"; then 187 | # $@ is not empty: it contains at least $arg. 188 | set fnord "$@" "$dst_arg" 189 | shift # fnord 190 | fi 191 | shift # arg 192 | dst_arg=$arg 193 | # Protect names problematic for 'test' and other utilities. 194 | case $dst_arg in 195 | -* | [=\(\)!]) dst_arg=./$dst_arg;; 196 | esac 197 | done 198 | fi 199 | 200 | if test $# -eq 0; then 201 | if test -z "$dir_arg"; then 202 | echo "$0: no input file specified." >&2 203 | exit 1 204 | fi 205 | # It's OK to call 'install-sh -d' without argument. 206 | # This can happen when creating conditional directories. 207 | exit 0 208 | fi 209 | 210 | if test -z "$dir_arg"; then 211 | do_exit='(exit $ret); exit $ret' 212 | trap "ret=129; $do_exit" 1 213 | trap "ret=130; $do_exit" 2 214 | trap "ret=141; $do_exit" 13 215 | trap "ret=143; $do_exit" 15 216 | 217 | # Set umask so as not to create temps with too-generous modes. 218 | # However, 'strip' requires both read and write access to temps. 219 | case $mode in 220 | # Optimize common cases. 221 | *644) cp_umask=133;; 222 | *755) cp_umask=22;; 223 | 224 | *[0-7]) 225 | if test -z "$stripcmd"; then 226 | u_plus_rw= 227 | else 228 | u_plus_rw='% 200' 229 | fi 230 | cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; 231 | *) 232 | if test -z "$stripcmd"; then 233 | u_plus_rw= 234 | else 235 | u_plus_rw=,u+rw 236 | fi 237 | cp_umask=$mode$u_plus_rw;; 238 | esac 239 | fi 240 | 241 | for src 242 | do 243 | # Protect names problematic for 'test' and other utilities. 244 | case $src in 245 | -* | [=\(\)!]) src=./$src;; 246 | esac 247 | 248 | if test -n "$dir_arg"; then 249 | dst=$src 250 | dstdir=$dst 251 | test -d "$dstdir" 252 | dstdir_status=$? 253 | else 254 | 255 | # Waiting for this to be detected by the "$cpprog $src $dsttmp" command 256 | # might cause directories to be created, which would be especially bad 257 | # if $src (and thus $dsttmp) contains '*'. 258 | if test ! -f "$src" && test ! -d "$src"; then 259 | echo "$0: $src does not exist." >&2 260 | exit 1 261 | fi 262 | 263 | if test -z "$dst_arg"; then 264 | echo "$0: no destination specified." >&2 265 | exit 1 266 | fi 267 | dst=$dst_arg 268 | 269 | # If destination is a directory, append the input filename; won't work 270 | # if double slashes aren't ignored. 271 | if test -d "$dst"; then 272 | if test -n "$no_target_directory"; then 273 | echo "$0: $dst_arg: Is a directory" >&2 274 | exit 1 275 | fi 276 | dstdir=$dst 277 | dst=$dstdir/`basename "$src"` 278 | dstdir_status=0 279 | else 280 | # Prefer dirname, but fall back on a substitute if dirname fails. 281 | dstdir=` 282 | (dirname "$dst") 2>/dev/null || 283 | expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ 284 | X"$dst" : 'X\(//\)[^/]' \| \ 285 | X"$dst" : 'X\(//\)$' \| \ 286 | X"$dst" : 'X\(/\)' \| . 2>/dev/null || 287 | echo X"$dst" | 288 | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ 289 | s//\1/ 290 | q 291 | } 292 | /^X\(\/\/\)[^/].*/{ 293 | s//\1/ 294 | q 295 | } 296 | /^X\(\/\/\)$/{ 297 | s//\1/ 298 | q 299 | } 300 | /^X\(\/\).*/{ 301 | s//\1/ 302 | q 303 | } 304 | s/.*/./; q' 305 | ` 306 | 307 | test -d "$dstdir" 308 | dstdir_status=$? 309 | fi 310 | fi 311 | 312 | obsolete_mkdir_used=false 313 | 314 | if test $dstdir_status != 0; then 315 | case $posix_mkdir in 316 | '') 317 | # Create intermediate dirs using mode 755 as modified by the umask. 318 | # This is like FreeBSD 'install' as of 1997-10-28. 319 | umask=`umask` 320 | case $stripcmd.$umask in 321 | # Optimize common cases. 322 | *[2367][2367]) mkdir_umask=$umask;; 323 | .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; 324 | 325 | *[0-7]) 326 | mkdir_umask=`expr $umask + 22 \ 327 | - $umask % 100 % 40 + $umask % 20 \ 328 | - $umask % 10 % 4 + $umask % 2 329 | `;; 330 | *) mkdir_umask=$umask,go-w;; 331 | esac 332 | 333 | # With -d, create the new directory with the user-specified mode. 334 | # Otherwise, rely on $mkdir_umask. 335 | if test -n "$dir_arg"; then 336 | mkdir_mode=-m$mode 337 | else 338 | mkdir_mode= 339 | fi 340 | 341 | posix_mkdir=false 342 | case $umask in 343 | *[123567][0-7][0-7]) 344 | # POSIX mkdir -p sets u+wx bits regardless of umask, which 345 | # is incompatible with FreeBSD 'install' when (umask & 300) != 0. 346 | ;; 347 | *) 348 | tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ 349 | trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 350 | 351 | if (umask $mkdir_umask && 352 | exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 353 | then 354 | if test -z "$dir_arg" || { 355 | # Check for POSIX incompatibilities with -m. 356 | # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or 357 | # other-writable bit of parent directory when it shouldn't. 358 | # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. 359 | ls_ld_tmpdir=`ls -ld "$tmpdir"` 360 | case $ls_ld_tmpdir in 361 | d????-?r-*) different_mode=700;; 362 | d????-?--*) different_mode=755;; 363 | *) false;; 364 | esac && 365 | $mkdirprog -m$different_mode -p -- "$tmpdir" && { 366 | ls_ld_tmpdir_1=`ls -ld "$tmpdir"` 367 | test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" 368 | } 369 | } 370 | then posix_mkdir=: 371 | fi 372 | rmdir "$tmpdir/d" "$tmpdir" 373 | else 374 | # Remove any dirs left behind by ancient mkdir implementations. 375 | rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null 376 | fi 377 | trap '' 0;; 378 | esac;; 379 | esac 380 | 381 | if 382 | $posix_mkdir && ( 383 | umask $mkdir_umask && 384 | $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" 385 | ) 386 | then : 387 | else 388 | 389 | # The umask is ridiculous, or mkdir does not conform to POSIX, 390 | # or it failed possibly due to a race condition. Create the 391 | # directory the slow way, step by step, checking for races as we go. 392 | 393 | case $dstdir in 394 | /*) prefix='/';; 395 | [-=\(\)!]*) prefix='./';; 396 | *) prefix='';; 397 | esac 398 | 399 | eval "$initialize_posix_glob" 400 | 401 | oIFS=$IFS 402 | IFS=/ 403 | $posix_glob set -f 404 | set fnord $dstdir 405 | shift 406 | $posix_glob set +f 407 | IFS=$oIFS 408 | 409 | prefixes= 410 | 411 | for d 412 | do 413 | test X"$d" = X && continue 414 | 415 | prefix=$prefix$d 416 | if test -d "$prefix"; then 417 | prefixes= 418 | else 419 | if $posix_mkdir; then 420 | (umask=$mkdir_umask && 421 | $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break 422 | # Don't fail if two instances are running concurrently. 423 | test -d "$prefix" || exit 1 424 | else 425 | case $prefix in 426 | *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; 427 | *) qprefix=$prefix;; 428 | esac 429 | prefixes="$prefixes '$qprefix'" 430 | fi 431 | fi 432 | prefix=$prefix/ 433 | done 434 | 435 | if test -n "$prefixes"; then 436 | # Don't fail if two instances are running concurrently. 437 | (umask $mkdir_umask && 438 | eval "\$doit_exec \$mkdirprog $prefixes") || 439 | test -d "$dstdir" || exit 1 440 | obsolete_mkdir_used=true 441 | fi 442 | fi 443 | fi 444 | 445 | if test -n "$dir_arg"; then 446 | { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && 447 | { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && 448 | { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || 449 | test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 450 | else 451 | 452 | # Make a couple of temp file names in the proper directory. 453 | dsttmp=$dstdir/_inst.$$_ 454 | rmtmp=$dstdir/_rm.$$_ 455 | 456 | # Trap to clean up those temp files at exit. 457 | trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 458 | 459 | # Copy the file name to the temp name. 460 | (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && 461 | 462 | # and set any options; do chmod last to preserve setuid bits. 463 | # 464 | # If any of these fail, we abort the whole thing. If we want to 465 | # ignore errors from any of these, just make sure not to ignore 466 | # errors from the above "$doit $cpprog $src $dsttmp" command. 467 | # 468 | { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && 469 | { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && 470 | { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && 471 | { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && 472 | 473 | # If -C, don't bother to copy if it wouldn't change the file. 474 | if $copy_on_change && 475 | old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && 476 | new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && 477 | 478 | eval "$initialize_posix_glob" && 479 | $posix_glob set -f && 480 | set X $old && old=:$2:$4:$5:$6 && 481 | set X $new && new=:$2:$4:$5:$6 && 482 | $posix_glob set +f && 483 | 484 | test "$old" = "$new" && 485 | $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 486 | then 487 | rm -f "$dsttmp" 488 | else 489 | # Rename the file to the real destination. 490 | $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || 491 | 492 | # The rename failed, perhaps because mv can't rename something else 493 | # to itself, or perhaps because mv is so ancient that it does not 494 | # support -f. 495 | { 496 | # Now remove or move aside any old file at destination location. 497 | # We try this two ways since rm can't unlink itself on some 498 | # systems and the destination file might be busy for other 499 | # reasons. In this case, the final cleanup might fail but the new 500 | # file should still install successfully. 501 | { 502 | test ! -f "$dst" || 503 | $doit $rmcmd -f "$dst" 2>/dev/null || 504 | { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && 505 | { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } 506 | } || 507 | { echo "$0: cannot unlink or rename $dst" >&2 508 | (exit 1); exit 1 509 | } 510 | } && 511 | 512 | # Now rename the file to the real destination. 513 | $doit $mvcmd "$dsttmp" "$dst" 514 | } 515 | fi || exit 1 516 | 517 | trap '' 0 518 | fi 519 | done 520 | 521 | # Local variables: 522 | # eval: (add-hook 'write-file-hooks 'time-stamp) 523 | # time-stamp-start: "scriptversion=" 524 | # time-stamp-format: "%:y-%02m-%02d.%02H" 525 | # time-stamp-time-zone: "UTC" 526 | # time-stamp-end: "; # UTC" 527 | # End: 528 | -------------------------------------------------------------------------------- /m4/ax_cxx_compile_stdcxx_11.m4: -------------------------------------------------------------------------------- 1 | # ============================================================================ 2 | # http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_11.html 3 | # ============================================================================ 4 | # 5 | # SYNOPSIS 6 | # 7 | # AX_CXX_COMPILE_STDCXX_11([ext|noext],[mandatory|optional]) 8 | # 9 | # DESCRIPTION 10 | # 11 | # Check for baseline language coverage in the compiler for the C++11 12 | # standard; if necessary, add switches to CXXFLAGS to enable support. 13 | # 14 | # The first argument, if specified, indicates whether you insist on an 15 | # extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g. 16 | # -std=c++11). If neither is specified, you get whatever works, with 17 | # preference for an extended mode. 18 | # 19 | # The second argument, if specified 'mandatory' or if left unspecified, 20 | # indicates that baseline C++11 support is required and that the macro 21 | # should error out if no mode with that support is found. If specified 22 | # 'optional', then configuration proceeds regardless, after defining 23 | # HAVE_CXX11 if and only if a supporting mode is found. 24 | # 25 | # LICENSE 26 | # 27 | # Copyright (c) 2008 Benjamin Kosnik 28 | # Copyright (c) 2012 Zack Weinberg 29 | # Copyright (c) 2013 Roy Stogner 30 | # Copyright (c) 2014 Alexey Sokolov 31 | # 32 | # Copying and distribution of this file, with or without modification, are 33 | # permitted in any medium without royalty provided the copyright notice 34 | # and this notice are preserved. This file is offered as-is, without any 35 | # warranty. 36 | 37 | #serial 4 38 | 39 | m4_define([_AX_CXX_COMPILE_STDCXX_11_testbody], [[ 40 | template 41 | struct check 42 | { 43 | static_assert(sizeof(int) <= sizeof(T), "not big enough"); 44 | }; 45 | 46 | struct Base { 47 | virtual void f() {} 48 | }; 49 | struct Child : public Base { 50 | virtual void f() override {} 51 | }; 52 | 53 | typedef check> right_angle_brackets; 54 | 55 | int a; 56 | decltype(a) b; 57 | 58 | typedef check check_type; 59 | check_type c; 60 | check_type&& cr = static_cast(c); 61 | 62 | auto d = a; 63 | auto l = [](){}; 64 | ]]) 65 | 66 | AC_DEFUN([AX_CXX_COMPILE_STDCXX_11], [dnl 67 | m4_if([$1], [], [], 68 | [$1], [ext], [], 69 | [$1], [noext], [], 70 | [m4_fatal([invalid argument `$1' to AX_CXX_COMPILE_STDCXX_11])])dnl 71 | m4_if([$2], [], [ax_cxx_compile_cxx11_required=true], 72 | [$2], [mandatory], [ax_cxx_compile_cxx11_required=true], 73 | [$2], [optional], [ax_cxx_compile_cxx11_required=false], 74 | [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX_11])]) 75 | AC_LANG_PUSH([C++])dnl 76 | ac_success=no 77 | AC_CACHE_CHECK(whether $CXX supports C++11 features by default, 78 | ax_cv_cxx_compile_cxx11, 79 | [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])], 80 | [ax_cv_cxx_compile_cxx11=yes], 81 | [ax_cv_cxx_compile_cxx11=no])]) 82 | if test x$ax_cv_cxx_compile_cxx11 = xyes; then 83 | ac_success=yes 84 | fi 85 | 86 | m4_if([$1], [noext], [], [dnl 87 | if test x$ac_success = xno; then 88 | for switch in -std=gnu++11 -std=gnu++0x; do 89 | cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch]) 90 | AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch, 91 | $cachevar, 92 | [ac_save_CXXFLAGS="$CXXFLAGS" 93 | CXXFLAGS="$CXXFLAGS $switch" 94 | AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])], 95 | [eval $cachevar=yes], 96 | [eval $cachevar=no]) 97 | CXXFLAGS="$ac_save_CXXFLAGS"]) 98 | if eval test x\$$cachevar = xyes; then 99 | CXXFLAGS="$CXXFLAGS $switch" 100 | ac_success=yes 101 | break 102 | fi 103 | done 104 | fi]) 105 | 106 | m4_if([$1], [ext], [], [dnl 107 | if test x$ac_success = xno; then 108 | for switch in -std=c++11 -std=c++0x; do 109 | cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch]) 110 | AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch, 111 | $cachevar, 112 | [ac_save_CXXFLAGS="$CXXFLAGS" 113 | CXXFLAGS="$CXXFLAGS $switch" 114 | AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])], 115 | [eval $cachevar=yes], 116 | [eval $cachevar=no]) 117 | CXXFLAGS="$ac_save_CXXFLAGS"]) 118 | if eval test x\$$cachevar = xyes; then 119 | CXXFLAGS="$CXXFLAGS $switch" 120 | ac_success=yes 121 | break 122 | fi 123 | done 124 | fi]) 125 | AC_LANG_POP([C++]) 126 | if test x$ax_cxx_compile_cxx11_required = xtrue; then 127 | if test x$ac_success = xno; then 128 | AC_MSG_ERROR([*** A compiler with support for C++11 language features is required.]) 129 | fi 130 | else 131 | if test x$ac_success = xno; then 132 | HAVE_CXX11=0 133 | AC_MSG_NOTICE([No compiler with C++11 support was found]) 134 | else 135 | HAVE_CXX11=1 136 | AC_DEFINE(HAVE_CXX11,1, 137 | [define if the compiler supports basic C++11 syntax]) 138 | fi 139 | 140 | AC_SUBST(HAVE_CXX11) 141 | fi 142 | ]) 143 | -------------------------------------------------------------------------------- /missing: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # Common wrapper for a few potentially missing GNU programs. 3 | 4 | scriptversion=2013-10-28.13; # UTC 5 | 6 | # Copyright (C) 1996-2013 Free Software Foundation, Inc. 7 | # Originally written by Fran,cois Pinard , 1996. 8 | 9 | # This program is free software; you can redistribute it and/or modify 10 | # it under the terms of the GNU General Public License as published by 11 | # the Free Software Foundation; either version 2, or (at your option) 12 | # any later version. 13 | 14 | # This program is distributed in the hope that it will be useful, 15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | # GNU General Public License for more details. 18 | 19 | # You should have received a copy of the GNU General Public License 20 | # along with this program. If not, see . 21 | 22 | # As a special exception to the GNU General Public License, if you 23 | # distribute this file as part of a program that contains a 24 | # configuration script generated by Autoconf, you may include it under 25 | # the same distribution terms that you use for the rest of that program. 26 | 27 | if test $# -eq 0; then 28 | echo 1>&2 "Try '$0 --help' for more information" 29 | exit 1 30 | fi 31 | 32 | case $1 in 33 | 34 | --is-lightweight) 35 | # Used by our autoconf macros to check whether the available missing 36 | # script is modern enough. 37 | exit 0 38 | ;; 39 | 40 | --run) 41 | # Back-compat with the calling convention used by older automake. 42 | shift 43 | ;; 44 | 45 | -h|--h|--he|--hel|--help) 46 | echo "\ 47 | $0 [OPTION]... PROGRAM [ARGUMENT]... 48 | 49 | Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due 50 | to PROGRAM being missing or too old. 51 | 52 | Options: 53 | -h, --help display this help and exit 54 | -v, --version output version information and exit 55 | 56 | Supported PROGRAM values: 57 | aclocal autoconf autoheader autom4te automake makeinfo 58 | bison yacc flex lex help2man 59 | 60 | Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and 61 | 'g' are ignored when checking the name. 62 | 63 | Send bug reports to ." 64 | exit $? 65 | ;; 66 | 67 | -v|--v|--ve|--ver|--vers|--versi|--versio|--version) 68 | echo "missing $scriptversion (GNU Automake)" 69 | exit $? 70 | ;; 71 | 72 | -*) 73 | echo 1>&2 "$0: unknown '$1' option" 74 | echo 1>&2 "Try '$0 --help' for more information" 75 | exit 1 76 | ;; 77 | 78 | esac 79 | 80 | # Run the given program, remember its exit status. 81 | "$@"; st=$? 82 | 83 | # If it succeeded, we are done. 84 | test $st -eq 0 && exit 0 85 | 86 | # Also exit now if we it failed (or wasn't found), and '--version' was 87 | # passed; such an option is passed most likely to detect whether the 88 | # program is present and works. 89 | case $2 in --version|--help) exit $st;; esac 90 | 91 | # Exit code 63 means version mismatch. This often happens when the user 92 | # tries to use an ancient version of a tool on a file that requires a 93 | # minimum version. 94 | if test $st -eq 63; then 95 | msg="probably too old" 96 | elif test $st -eq 127; then 97 | # Program was missing. 98 | msg="missing on your system" 99 | else 100 | # Program was found and executed, but failed. Give up. 101 | exit $st 102 | fi 103 | 104 | perl_URL=http://www.perl.org/ 105 | flex_URL=http://flex.sourceforge.net/ 106 | gnu_software_URL=http://www.gnu.org/software 107 | 108 | program_details () 109 | { 110 | case $1 in 111 | aclocal|automake) 112 | echo "The '$1' program is part of the GNU Automake package:" 113 | echo "<$gnu_software_URL/automake>" 114 | echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:" 115 | echo "<$gnu_software_URL/autoconf>" 116 | echo "<$gnu_software_URL/m4/>" 117 | echo "<$perl_URL>" 118 | ;; 119 | autoconf|autom4te|autoheader) 120 | echo "The '$1' program is part of the GNU Autoconf package:" 121 | echo "<$gnu_software_URL/autoconf/>" 122 | echo "It also requires GNU m4 and Perl in order to run:" 123 | echo "<$gnu_software_URL/m4/>" 124 | echo "<$perl_URL>" 125 | ;; 126 | esac 127 | } 128 | 129 | give_advice () 130 | { 131 | # Normalize program name to check for. 132 | normalized_program=`echo "$1" | sed ' 133 | s/^gnu-//; t 134 | s/^gnu//; t 135 | s/^g//; t'` 136 | 137 | printf '%s\n' "'$1' is $msg." 138 | 139 | configure_deps="'configure.ac' or m4 files included by 'configure.ac'" 140 | case $normalized_program in 141 | autoconf*) 142 | echo "You should only need it if you modified 'configure.ac'," 143 | echo "or m4 files included by it." 144 | program_details 'autoconf' 145 | ;; 146 | autoheader*) 147 | echo "You should only need it if you modified 'acconfig.h' or" 148 | echo "$configure_deps." 149 | program_details 'autoheader' 150 | ;; 151 | automake*) 152 | echo "You should only need it if you modified 'Makefile.am' or" 153 | echo "$configure_deps." 154 | program_details 'automake' 155 | ;; 156 | aclocal*) 157 | echo "You should only need it if you modified 'acinclude.m4' or" 158 | echo "$configure_deps." 159 | program_details 'aclocal' 160 | ;; 161 | autom4te*) 162 | echo "You might have modified some maintainer files that require" 163 | echo "the 'autom4te' program to be rebuilt." 164 | program_details 'autom4te' 165 | ;; 166 | bison*|yacc*) 167 | echo "You should only need it if you modified a '.y' file." 168 | echo "You may want to install the GNU Bison package:" 169 | echo "<$gnu_software_URL/bison/>" 170 | ;; 171 | lex*|flex*) 172 | echo "You should only need it if you modified a '.l' file." 173 | echo "You may want to install the Fast Lexical Analyzer package:" 174 | echo "<$flex_URL>" 175 | ;; 176 | help2man*) 177 | echo "You should only need it if you modified a dependency" \ 178 | "of a man page." 179 | echo "You may want to install the GNU Help2man package:" 180 | echo "<$gnu_software_URL/help2man/>" 181 | ;; 182 | makeinfo*) 183 | echo "You should only need it if you modified a '.texi' file, or" 184 | echo "any other file indirectly affecting the aspect of the manual." 185 | echo "You might want to install the Texinfo package:" 186 | echo "<$gnu_software_URL/texinfo/>" 187 | echo "The spurious makeinfo call might also be the consequence of" 188 | echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might" 189 | echo "want to install GNU make:" 190 | echo "<$gnu_software_URL/make/>" 191 | ;; 192 | *) 193 | echo "You might have modified some files without having the proper" 194 | echo "tools for further handling them. Check the 'README' file, it" 195 | echo "often tells you about the needed prerequisites for installing" 196 | echo "this package. You may also peek at any GNU archive site, in" 197 | echo "case some other package contains this missing '$1' program." 198 | ;; 199 | esac 200 | } 201 | 202 | give_advice "$1" | sed -e '1s/^/WARNING: /' \ 203 | -e '2,$s/^/ /' >&2 204 | 205 | # Propagate the correct exit status (expected to be 127 for a program 206 | # not found, 63 for a program that failed due to version mismatch). 207 | exit $st 208 | 209 | # Local variables: 210 | # eval: (add-hook 'write-file-hooks 'time-stamp) 211 | # time-stamp-start: "scriptversion=" 212 | # time-stamp-format: "%:y-%02m-%02d.%02H" 213 | # time-stamp-time-zone: "UTC" 214 | # time-stamp-end: "; # UTC" 215 | # End: 216 | -------------------------------------------------------------------------------- /src/Makefile.am: -------------------------------------------------------------------------------- 1 | AUTOMAKE_OPTIONS = foreign 2 | #ACLOCAL_AMFLAGS = -I m4 3 | AM_CXXFLAGS=-Wall -DVERSION=\"$(VERSION)\" -DPROG="\"$(PACKAGE)\"" 4 | LDADD=-ltag -lz 5 | bin_PROGRAMS = metadsf 6 | metadsf_SOURCES = dsffile.cpp dsfheader.cpp dsfproperties.cpp main.cpp metadsf.cpp options.cpp utils.cpp 7 | -------------------------------------------------------------------------------- /src/Makefile.in: -------------------------------------------------------------------------------- 1 | # Makefile.in generated by automake 1.14.1 from Makefile.am. 2 | # @configure_input@ 3 | 4 | # Copyright (C) 1994-2013 Free Software Foundation, Inc. 5 | 6 | # This Makefile.in is free software; the Free Software Foundation 7 | # gives unlimited permission to copy and/or distribute it, 8 | # with or without modifications, as long as this notice is preserved. 9 | 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY, to the extent permitted by law; without 12 | # even the implied warranty of MERCHANTABILITY or FITNESS FOR A 13 | # PARTICULAR PURPOSE. 14 | 15 | @SET_MAKE@ 16 | 17 | VPATH = @srcdir@ 18 | am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' 19 | am__make_running_with_option = \ 20 | case $${target_option-} in \ 21 | ?) ;; \ 22 | *) echo "am__make_running_with_option: internal error: invalid" \ 23 | "target option '$${target_option-}' specified" >&2; \ 24 | exit 1;; \ 25 | esac; \ 26 | has_opt=no; \ 27 | sane_makeflags=$$MAKEFLAGS; \ 28 | if $(am__is_gnu_make); then \ 29 | sane_makeflags=$$MFLAGS; \ 30 | else \ 31 | case $$MAKEFLAGS in \ 32 | *\\[\ \ ]*) \ 33 | bs=\\; \ 34 | sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ 35 | | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ 36 | esac; \ 37 | fi; \ 38 | skip_next=no; \ 39 | strip_trailopt () \ 40 | { \ 41 | flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ 42 | }; \ 43 | for flg in $$sane_makeflags; do \ 44 | test $$skip_next = yes && { skip_next=no; continue; }; \ 45 | case $$flg in \ 46 | *=*|--*) continue;; \ 47 | -*I) strip_trailopt 'I'; skip_next=yes;; \ 48 | -*I?*) strip_trailopt 'I';; \ 49 | -*O) strip_trailopt 'O'; skip_next=yes;; \ 50 | -*O?*) strip_trailopt 'O';; \ 51 | -*l) strip_trailopt 'l'; skip_next=yes;; \ 52 | -*l?*) strip_trailopt 'l';; \ 53 | -[dEDm]) skip_next=yes;; \ 54 | -[JT]) skip_next=yes;; \ 55 | esac; \ 56 | case $$flg in \ 57 | *$$target_option*) has_opt=yes; break;; \ 58 | esac; \ 59 | done; \ 60 | test $$has_opt = yes 61 | am__make_dryrun = (target_option=n; $(am__make_running_with_option)) 62 | am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) 63 | pkgdatadir = $(datadir)/@PACKAGE@ 64 | pkgincludedir = $(includedir)/@PACKAGE@ 65 | pkglibdir = $(libdir)/@PACKAGE@ 66 | pkglibexecdir = $(libexecdir)/@PACKAGE@ 67 | am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd 68 | install_sh_DATA = $(install_sh) -c -m 644 69 | install_sh_PROGRAM = $(install_sh) -c 70 | install_sh_SCRIPT = $(install_sh) -c 71 | INSTALL_HEADER = $(INSTALL_DATA) 72 | transform = $(program_transform_name) 73 | NORMAL_INSTALL = : 74 | PRE_INSTALL = : 75 | POST_INSTALL = : 76 | NORMAL_UNINSTALL = : 77 | PRE_UNINSTALL = : 78 | POST_UNINSTALL = : 79 | bin_PROGRAMS = metadsf$(EXEEXT) 80 | subdir = src 81 | DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ 82 | $(top_srcdir)/depcomp 83 | ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 84 | am__aclocal_m4_deps = $(top_srcdir)/configure.ac 85 | am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ 86 | $(ACLOCAL_M4) 87 | mkinstalldirs = $(install_sh) -d 88 | CONFIG_CLEAN_FILES = 89 | CONFIG_CLEAN_VPATH_FILES = 90 | am__installdirs = "$(DESTDIR)$(bindir)" 91 | PROGRAMS = $(bin_PROGRAMS) 92 | am_metadsf_OBJECTS = dsffile.$(OBJEXT) dsfheader.$(OBJEXT) \ 93 | dsfproperties.$(OBJEXT) main.$(OBJEXT) metadsf.$(OBJEXT) \ 94 | options.$(OBJEXT) utils.$(OBJEXT) 95 | metadsf_OBJECTS = $(am_metadsf_OBJECTS) 96 | metadsf_LDADD = $(LDADD) 97 | AM_V_P = $(am__v_P_@AM_V@) 98 | am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) 99 | am__v_P_0 = false 100 | am__v_P_1 = : 101 | AM_V_GEN = $(am__v_GEN_@AM_V@) 102 | am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) 103 | am__v_GEN_0 = @echo " GEN " $@; 104 | am__v_GEN_1 = 105 | AM_V_at = $(am__v_at_@AM_V@) 106 | am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) 107 | am__v_at_0 = @ 108 | am__v_at_1 = 109 | DEFAULT_INCLUDES = -I.@am__isrc@ 110 | depcomp = $(SHELL) $(top_srcdir)/depcomp 111 | am__depfiles_maybe = depfiles 112 | am__mv = mv -f 113 | CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ 114 | $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) 115 | AM_V_CXX = $(am__v_CXX_@AM_V@) 116 | am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@) 117 | am__v_CXX_0 = @echo " CXX " $@; 118 | am__v_CXX_1 = 119 | CXXLD = $(CXX) 120 | CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ 121 | -o $@ 122 | AM_V_CXXLD = $(am__v_CXXLD_@AM_V@) 123 | am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@) 124 | am__v_CXXLD_0 = @echo " CXXLD " $@; 125 | am__v_CXXLD_1 = 126 | SOURCES = $(metadsf_SOURCES) 127 | DIST_SOURCES = $(metadsf_SOURCES) 128 | am__can_run_installinfo = \ 129 | case $$AM_UPDATE_INFO_DIR in \ 130 | n|no|NO) false;; \ 131 | *) (install-info --version) >/dev/null 2>&1;; \ 132 | esac 133 | am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) 134 | # Read a list of newline-separated strings from the standard input, 135 | # and print each of them once, without duplicates. Input order is 136 | # *not* preserved. 137 | am__uniquify_input = $(AWK) '\ 138 | BEGIN { nonempty = 0; } \ 139 | { items[$$0] = 1; nonempty = 1; } \ 140 | END { if (nonempty) { for (i in items) print i; }; } \ 141 | ' 142 | # Make sure the list of sources is unique. This is necessary because, 143 | # e.g., the same source file might be shared among _SOURCES variables 144 | # for different programs/libraries. 145 | am__define_uniq_tagged_files = \ 146 | list='$(am__tagged_files)'; \ 147 | unique=`for i in $$list; do \ 148 | if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ 149 | done | $(am__uniquify_input)` 150 | ETAGS = etags 151 | CTAGS = ctags 152 | DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) 153 | ACLOCAL = @ACLOCAL@ 154 | AMTAR = @AMTAR@ 155 | AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ 156 | AUTOCONF = @AUTOCONF@ 157 | AUTOHEADER = @AUTOHEADER@ 158 | AUTOMAKE = @AUTOMAKE@ 159 | AWK = @AWK@ 160 | CC = @CC@ 161 | CCDEPMODE = @CCDEPMODE@ 162 | CFLAGS = @CFLAGS@ 163 | CPPFLAGS = @CPPFLAGS@ 164 | CXX = @CXX@ 165 | CXXCPP = @CXXCPP@ 166 | CXXDEPMODE = @CXXDEPMODE@ 167 | CXXFLAGS = @CXXFLAGS@ 168 | CYGPATH_W = @CYGPATH_W@ 169 | DEFS = @DEFS@ 170 | DEPDIR = @DEPDIR@ 171 | ECHO_C = @ECHO_C@ 172 | ECHO_N = @ECHO_N@ 173 | ECHO_T = @ECHO_T@ 174 | EGREP = @EGREP@ 175 | EXEEXT = @EXEEXT@ 176 | GREP = @GREP@ 177 | HAVE_CXX11 = @HAVE_CXX11@ 178 | INSTALL = @INSTALL@ 179 | INSTALL_DATA = @INSTALL_DATA@ 180 | INSTALL_PROGRAM = @INSTALL_PROGRAM@ 181 | INSTALL_SCRIPT = @INSTALL_SCRIPT@ 182 | INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ 183 | LDFLAGS = @LDFLAGS@ 184 | LIBOBJS = @LIBOBJS@ 185 | LIBS = @LIBS@ 186 | LTLIBOBJS = @LTLIBOBJS@ 187 | MAKEINFO = @MAKEINFO@ 188 | MKDIR_P = @MKDIR_P@ 189 | OBJEXT = @OBJEXT@ 190 | PACKAGE = @PACKAGE@ 191 | PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ 192 | PACKAGE_NAME = @PACKAGE_NAME@ 193 | PACKAGE_STRING = @PACKAGE_STRING@ 194 | PACKAGE_TARNAME = @PACKAGE_TARNAME@ 195 | PACKAGE_URL = @PACKAGE_URL@ 196 | PACKAGE_VERSION = @PACKAGE_VERSION@ 197 | PATH_SEPARATOR = @PATH_SEPARATOR@ 198 | SET_MAKE = @SET_MAKE@ 199 | SHELL = @SHELL@ 200 | STRIP = @STRIP@ 201 | VERSION = @VERSION@ 202 | abs_builddir = @abs_builddir@ 203 | abs_srcdir = @abs_srcdir@ 204 | abs_top_builddir = @abs_top_builddir@ 205 | abs_top_srcdir = @abs_top_srcdir@ 206 | ac_ct_CC = @ac_ct_CC@ 207 | ac_ct_CXX = @ac_ct_CXX@ 208 | am__include = @am__include@ 209 | am__leading_dot = @am__leading_dot@ 210 | am__quote = @am__quote@ 211 | am__tar = @am__tar@ 212 | am__untar = @am__untar@ 213 | bindir = @bindir@ 214 | build_alias = @build_alias@ 215 | builddir = @builddir@ 216 | datadir = @datadir@ 217 | datarootdir = @datarootdir@ 218 | docdir = @docdir@ 219 | dvidir = @dvidir@ 220 | exec_prefix = @exec_prefix@ 221 | host_alias = @host_alias@ 222 | htmldir = @htmldir@ 223 | includedir = @includedir@ 224 | infodir = @infodir@ 225 | install_sh = @install_sh@ 226 | libdir = @libdir@ 227 | libexecdir = @libexecdir@ 228 | localedir = @localedir@ 229 | localstatedir = @localstatedir@ 230 | mandir = @mandir@ 231 | mkdir_p = @mkdir_p@ 232 | oldincludedir = @oldincludedir@ 233 | pdfdir = @pdfdir@ 234 | prefix = @prefix@ 235 | program_transform_name = @program_transform_name@ 236 | psdir = @psdir@ 237 | sbindir = @sbindir@ 238 | sharedstatedir = @sharedstatedir@ 239 | srcdir = @srcdir@ 240 | sysconfdir = @sysconfdir@ 241 | target_alias = @target_alias@ 242 | top_build_prefix = @top_build_prefix@ 243 | top_builddir = @top_builddir@ 244 | top_srcdir = @top_srcdir@ 245 | AUTOMAKE_OPTIONS = foreign 246 | ACLOCAL_AMFLAGS = -I /Users/gordonlo/dev/m4 247 | AM_CXXFLAGS = -Wall -I/usr/local/include -DVERSION=\"$(VERSION)\" -DPROG="\"$(PACKAGE)\"" 248 | AM_LDFLAGS = -L/usr/local/lib -ltag -lz 249 | metadsf_SOURCES = dsffile.cpp dsfheader.cpp dsfproperties.cpp main.cpp metadsf.cpp options.cpp utils.cpp 250 | all: all-am 251 | 252 | .SUFFIXES: 253 | .SUFFIXES: .cpp .o .obj 254 | $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) 255 | @for dep in $?; do \ 256 | case '$(am__configure_deps)' in \ 257 | *$$dep*) \ 258 | ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ 259 | && { if test -f $@; then exit 0; else break; fi; }; \ 260 | exit 1;; \ 261 | esac; \ 262 | done; \ 263 | echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/Makefile'; \ 264 | $(am__cd) $(top_srcdir) && \ 265 | $(AUTOMAKE) --foreign src/Makefile 266 | .PRECIOUS: Makefile 267 | Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status 268 | @case '$?' in \ 269 | *config.status*) \ 270 | cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ 271 | *) \ 272 | echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ 273 | cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ 274 | esac; 275 | 276 | $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) 277 | cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh 278 | 279 | $(top_srcdir)/configure: $(am__configure_deps) 280 | cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh 281 | $(ACLOCAL_M4): $(am__aclocal_m4_deps) 282 | cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh 283 | $(am__aclocal_m4_deps): 284 | install-binPROGRAMS: $(bin_PROGRAMS) 285 | @$(NORMAL_INSTALL) 286 | @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ 287 | if test -n "$$list"; then \ 288 | echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ 289 | $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ 290 | fi; \ 291 | for p in $$list; do echo "$$p $$p"; done | \ 292 | sed 's/$(EXEEXT)$$//' | \ 293 | while read p p1; do if test -f $$p \ 294 | ; then echo "$$p"; echo "$$p"; else :; fi; \ 295 | done | \ 296 | sed -e 'p;s,.*/,,;n;h' \ 297 | -e 's|.*|.|' \ 298 | -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ 299 | sed 'N;N;N;s,\n, ,g' | \ 300 | $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ 301 | { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ 302 | if ($$2 == $$4) files[d] = files[d] " " $$1; \ 303 | else { print "f", $$3 "/" $$4, $$1; } } \ 304 | END { for (d in files) print "f", d, files[d] }' | \ 305 | while read type dir files; do \ 306 | if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ 307 | test -z "$$files" || { \ 308 | echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ 309 | $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ 310 | } \ 311 | ; done 312 | 313 | uninstall-binPROGRAMS: 314 | @$(NORMAL_UNINSTALL) 315 | @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ 316 | files=`for p in $$list; do echo "$$p"; done | \ 317 | sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ 318 | -e 's/$$/$(EXEEXT)/' \ 319 | `; \ 320 | test -n "$$list" || exit 0; \ 321 | echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ 322 | cd "$(DESTDIR)$(bindir)" && rm -f $$files 323 | 324 | clean-binPROGRAMS: 325 | -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) 326 | 327 | metadsf$(EXEEXT): $(metadsf_OBJECTS) $(metadsf_DEPENDENCIES) $(EXTRA_metadsf_DEPENDENCIES) 328 | @rm -f metadsf$(EXEEXT) 329 | $(AM_V_CXXLD)$(CXXLINK) $(metadsf_OBJECTS) $(metadsf_LDADD) $(LIBS) 330 | 331 | mostlyclean-compile: 332 | -rm -f *.$(OBJEXT) 333 | 334 | distclean-compile: 335 | -rm -f *.tab.c 336 | 337 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dsffile.Po@am__quote@ 338 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dsfheader.Po@am__quote@ 339 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dsfproperties.Po@am__quote@ 340 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@ 341 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/metadsf.Po@am__quote@ 342 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/options.Po@am__quote@ 343 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/utils.Po@am__quote@ 344 | 345 | .cpp.o: 346 | @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< 347 | @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po 348 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ 349 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ 350 | @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $< 351 | 352 | .cpp.obj: 353 | @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` 354 | @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po 355 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ 356 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ 357 | @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` 358 | 359 | ID: $(am__tagged_files) 360 | $(am__define_uniq_tagged_files); mkid -fID $$unique 361 | tags: tags-am 362 | TAGS: tags 363 | 364 | tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) 365 | set x; \ 366 | here=`pwd`; \ 367 | $(am__define_uniq_tagged_files); \ 368 | shift; \ 369 | if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ 370 | test -n "$$unique" || unique=$$empty_fix; \ 371 | if test $$# -gt 0; then \ 372 | $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ 373 | "$$@" $$unique; \ 374 | else \ 375 | $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ 376 | $$unique; \ 377 | fi; \ 378 | fi 379 | ctags: ctags-am 380 | 381 | CTAGS: ctags 382 | ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) 383 | $(am__define_uniq_tagged_files); \ 384 | test -z "$(CTAGS_ARGS)$$unique" \ 385 | || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ 386 | $$unique 387 | 388 | GTAGS: 389 | here=`$(am__cd) $(top_builddir) && pwd` \ 390 | && $(am__cd) $(top_srcdir) \ 391 | && gtags -i $(GTAGS_ARGS) "$$here" 392 | cscopelist: cscopelist-am 393 | 394 | cscopelist-am: $(am__tagged_files) 395 | list='$(am__tagged_files)'; \ 396 | case "$(srcdir)" in \ 397 | [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ 398 | *) sdir=$(subdir)/$(srcdir) ;; \ 399 | esac; \ 400 | for i in $$list; do \ 401 | if test -f "$$i"; then \ 402 | echo "$(subdir)/$$i"; \ 403 | else \ 404 | echo "$$sdir/$$i"; \ 405 | fi; \ 406 | done >> $(top_builddir)/cscope.files 407 | 408 | distclean-tags: 409 | -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags 410 | 411 | distdir: $(DISTFILES) 412 | @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ 413 | topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ 414 | list='$(DISTFILES)'; \ 415 | dist_files=`for file in $$list; do echo $$file; done | \ 416 | sed -e "s|^$$srcdirstrip/||;t" \ 417 | -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ 418 | case $$dist_files in \ 419 | */*) $(MKDIR_P) `echo "$$dist_files" | \ 420 | sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ 421 | sort -u` ;; \ 422 | esac; \ 423 | for file in $$dist_files; do \ 424 | if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ 425 | if test -d $$d/$$file; then \ 426 | dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ 427 | if test -d "$(distdir)/$$file"; then \ 428 | find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ 429 | fi; \ 430 | if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ 431 | cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ 432 | find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ 433 | fi; \ 434 | cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ 435 | else \ 436 | test -f "$(distdir)/$$file" \ 437 | || cp -p $$d/$$file "$(distdir)/$$file" \ 438 | || exit 1; \ 439 | fi; \ 440 | done 441 | check-am: all-am 442 | check: check-am 443 | all-am: Makefile $(PROGRAMS) 444 | installdirs: 445 | for dir in "$(DESTDIR)$(bindir)"; do \ 446 | test -z "$$dir" || $(MKDIR_P) "$$dir"; \ 447 | done 448 | install: install-am 449 | install-exec: install-exec-am 450 | install-data: install-data-am 451 | uninstall: uninstall-am 452 | 453 | install-am: all-am 454 | @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am 455 | 456 | installcheck: installcheck-am 457 | install-strip: 458 | if test -z '$(STRIP)'; then \ 459 | $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ 460 | install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ 461 | install; \ 462 | else \ 463 | $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ 464 | install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ 465 | "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ 466 | fi 467 | mostlyclean-generic: 468 | 469 | clean-generic: 470 | 471 | distclean-generic: 472 | -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) 473 | -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) 474 | 475 | maintainer-clean-generic: 476 | @echo "This command is intended for maintainers to use" 477 | @echo "it deletes files that may require special tools to rebuild." 478 | clean: clean-am 479 | 480 | clean-am: clean-binPROGRAMS clean-generic mostlyclean-am 481 | 482 | distclean: distclean-am 483 | -rm -rf ./$(DEPDIR) 484 | -rm -f Makefile 485 | distclean-am: clean-am distclean-compile distclean-generic \ 486 | distclean-tags 487 | 488 | dvi: dvi-am 489 | 490 | dvi-am: 491 | 492 | html: html-am 493 | 494 | html-am: 495 | 496 | info: info-am 497 | 498 | info-am: 499 | 500 | install-data-am: 501 | 502 | install-dvi: install-dvi-am 503 | 504 | install-dvi-am: 505 | 506 | install-exec-am: install-binPROGRAMS 507 | 508 | install-html: install-html-am 509 | 510 | install-html-am: 511 | 512 | install-info: install-info-am 513 | 514 | install-info-am: 515 | 516 | install-man: 517 | 518 | install-pdf: install-pdf-am 519 | 520 | install-pdf-am: 521 | 522 | install-ps: install-ps-am 523 | 524 | install-ps-am: 525 | 526 | installcheck-am: 527 | 528 | maintainer-clean: maintainer-clean-am 529 | -rm -rf ./$(DEPDIR) 530 | -rm -f Makefile 531 | maintainer-clean-am: distclean-am maintainer-clean-generic 532 | 533 | mostlyclean: mostlyclean-am 534 | 535 | mostlyclean-am: mostlyclean-compile mostlyclean-generic 536 | 537 | pdf: pdf-am 538 | 539 | pdf-am: 540 | 541 | ps: ps-am 542 | 543 | ps-am: 544 | 545 | uninstall-am: uninstall-binPROGRAMS 546 | 547 | .MAKE: install-am install-strip 548 | 549 | .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean \ 550 | clean-binPROGRAMS clean-generic cscopelist-am ctags ctags-am \ 551 | distclean distclean-compile distclean-generic distclean-tags \ 552 | distdir dvi dvi-am html html-am info info-am install \ 553 | install-am install-binPROGRAMS install-data install-data-am \ 554 | install-dvi install-dvi-am install-exec install-exec-am \ 555 | install-html install-html-am install-info install-info-am \ 556 | install-man install-pdf install-pdf-am install-ps \ 557 | install-ps-am install-strip installcheck installcheck-am \ 558 | installdirs maintainer-clean maintainer-clean-generic \ 559 | mostlyclean mostlyclean-compile mostlyclean-generic pdf pdf-am \ 560 | ps ps-am tags tags-am uninstall uninstall-am \ 561 | uninstall-binPROGRAMS 562 | 563 | 564 | # Tell versions [3.59,3.63) of GNU make to not export all variables. 565 | # Otherwise a system limit (for SysV at least) may be exceeded. 566 | .NOEXPORT: 567 | -------------------------------------------------------------------------------- /src/dsffile.cpp: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | copyright : (C) 2014 by Peking Duck Labs 3 | email : pekingducklabs@gmail.com 4 | ***************************************************************************/ 5 | 6 | /*************************************************************************** 7 | * This library is free software; you can redistribute it and/or modify * 8 | * it under the terms of the GNU Lesser General Public License version * 9 | * 2.1 as published by the Free Software Foundation. * 10 | * * 11 | * This library is distributed in the hope that it will be useful, but * 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of * 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 14 | * Lesser General Public License for more details. * 15 | * * 16 | * You should have received a copy of the GNU Lesser General Public * 17 | * License along with this library; if not, write to the Free Software * 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 19 | * 02110-1301 USA * 20 | ***************************************************************************/ 21 | 22 | #include 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | #include 29 | 30 | #include "dsffile.h" 31 | #include "dsfheader.h" 32 | 33 | //using namespace TagLib; 34 | 35 | class DSFFile::FilePrivate 36 | { 37 | public: 38 | FilePrivate(TagLib::ID3v2::FrameFactory *frameFactory 39 | = TagLib::ID3v2::FrameFactory::instance()) : 40 | ID3v2FrameFactory(frameFactory), 41 | ID3v2Location(0), 42 | ID3v2OriginalSize(0), 43 | fileSize(0), 44 | tag(0), 45 | hasID3v2(false), 46 | properties(0) 47 | {} 48 | 49 | ~FilePrivate() 50 | { 51 | if (properties) delete properties; 52 | if (tag) delete tag; 53 | } 54 | 55 | const TagLib::ID3v2::FrameFactory *ID3v2FrameFactory; 56 | 57 | uint64_t ID3v2Location; // For DSD it's always > 0 if tag is present 58 | uint64_t ID3v2OriginalSize; 59 | uint64_t fileSize; 60 | TagLib::ID3v2::Tag *tag; 61 | 62 | // These indicate whether the file *on disk* has these tags, not if 63 | // this data structure does. This is used in computing offsets. 64 | 65 | bool hasID3v2; 66 | 67 | DSFProperties *properties; 68 | 69 | static inline TagLib::ByteVector& uint64ToVector(uint64_t num, 70 | TagLib::ByteVector &v) 71 | { 72 | char raw[8]; 73 | 74 | for (int i = 0; i < 8; i++) { 75 | raw[i] = ((0xff << (i * 8)) & num) >> (i * 8); 76 | } 77 | v.setData(raw, 8); 78 | return v; 79 | } 80 | 81 | // 82 | // ID3v2::Tag::render() fills up space previous occupied by 83 | // deleted frames with 0's, presumably to avoid rewriting 84 | // all audio data (in an mp3 file, the ID3v2 tag comes before the audio 85 | // data). 86 | // However in a DSD file the ID3v2 chunk is located at the end. 87 | // 88 | // This function attempts to shrink the ID3v2 Tag by replacing 89 | // the old ID3v2::Tag object with a new one to free up that space. 90 | // 91 | void shrinkTag(); 92 | }; 93 | 94 | void DSFFile::FilePrivate::shrinkTag() { 95 | TagLib::ID3v2::FrameList olist = tag->frameList(); 96 | TagLib::ID3v2::FrameList nlist; 97 | TagLib::ID3v2::FrameList::ConstIterator it; 98 | 99 | for (it = olist.begin(); it != olist.end(); it++) { 100 | nlist.append(*it); 101 | } 102 | 103 | TagLib::ID3v2::Tag *ntag = new TagLib::ID3v2::Tag(); 104 | for (it = nlist.begin(); it != nlist.end(); it++) { 105 | tag->removeFrame(*it, false); // Don't delete, just transfer the ownership 106 | ntag->addFrame(*it); 107 | } 108 | 109 | delete tag; 110 | tag = ntag; 111 | } 112 | 113 | 114 | //////////////////////////////////////////////////////////////////////////////// 115 | // public members 116 | //////////////////////////////////////////////////////////////////////////////// 117 | 118 | DSFFile::DSFFile(TagLib::FileName file, bool readProperties, 119 | TagLib::AudioProperties::ReadStyle propertiesStyle) 120 | : TagLib::File(file) 121 | { 122 | d = new FilePrivate; 123 | 124 | if(isOpen()) 125 | read(readProperties, propertiesStyle); 126 | } 127 | 128 | DSFFile::DSFFile(TagLib::FileName file, 129 | TagLib::ID3v2::FrameFactory *frameFactory, 130 | bool readProperties, 131 | TagLib::AudioProperties::ReadStyle propertiesStyle) : 132 | TagLib::File(file) 133 | { 134 | d = new FilePrivate(frameFactory); 135 | 136 | if(isOpen()) 137 | read(readProperties, propertiesStyle); 138 | } 139 | 140 | DSFFile::DSFFile(TagLib::IOStream *stream, 141 | TagLib::ID3v2::FrameFactory *frameFactory, 142 | bool readProperties, 143 | TagLib::AudioProperties::ReadStyle propertiesStyle) : 144 | TagLib::File(stream) 145 | { 146 | d = new FilePrivate(frameFactory); 147 | 148 | if(isOpen()) 149 | read(readProperties, propertiesStyle); 150 | } 151 | 152 | DSFFile::~DSFFile() 153 | { 154 | delete d; 155 | } 156 | 157 | TagLib::Tag *DSFFile::tag() const 158 | { 159 | return d->tag; 160 | } 161 | 162 | TagLib::PropertyMap DSFFile::properties() const 163 | { 164 | if(d->hasID3v2) 165 | return d->tag->properties(); 166 | return TagLib::PropertyMap(); 167 | } 168 | 169 | void DSFFile::removeUnsupportedProperties(const TagLib::StringList &properties) 170 | { 171 | if(d->hasID3v2) 172 | d->tag->removeUnsupportedProperties(properties); 173 | } 174 | 175 | TagLib::PropertyMap DSFFile::setProperties(const TagLib::PropertyMap &properties) 176 | { 177 | return d->tag->setProperties(properties); 178 | } 179 | 180 | TagLib::AudioProperties *DSFFile::audioProperties() const 181 | { 182 | return d->properties; 183 | } 184 | 185 | bool DSFFile::save() 186 | { 187 | return save(4); 188 | } 189 | 190 | bool DSFFile::save(int id3v2Version, bool shrink) 191 | { 192 | if(readOnly()) { 193 | std::cerr << "DSFFile::save() -- File is read only." << std::endl; 194 | return false; 195 | } 196 | 197 | bool success = true; 198 | 199 | if(ID3v2Tag() && !ID3v2Tag()->isEmpty()) { 200 | if (shrink) // remove padding 0's 201 | d->shrinkTag(); 202 | 203 | TagLib::ByteVector id3v2_v = ID3v2Tag()->render(id3v2Version); 204 | uint64_t fileSize = d->fileSize + id3v2_v.size() - d->ID3v2OriginalSize; 205 | TagLib::ByteVector fileSize_v; 206 | 207 | // Write new file size to DSD header 208 | DSFFile::FilePrivate::uint64ToVector(fileSize, fileSize_v); 209 | insert(fileSize_v, 12, DSFHeader::LONG_INT_SIZE); 210 | 211 | // The file didn't have an ID3v2 metadata block 212 | // Make the offset point to the end of file 213 | if (d->ID3v2Location == 0) { 214 | d->ID3v2Location = d->fileSize; 215 | 216 | TagLib::ByteVector offset_v; 217 | DSFFile::FilePrivate::uint64ToVector(d->fileSize, offset_v); 218 | insert(offset_v, 20, DSFHeader::LONG_INT_SIZE); 219 | } 220 | 221 | // Write ID3v2 to the end of the file 222 | insert(id3v2_v, d->ID3v2Location, d->ID3v2OriginalSize); 223 | 224 | // Reset header info 225 | d->fileSize = fileSize; 226 | d->ID3v2OriginalSize = id3v2_v.size(); 227 | d->hasID3v2 = true; 228 | } else { 229 | // 230 | // All frames have been deleted. Remove ID3v2 block 231 | // 232 | 233 | TagLib::ByteVector nulls_v(DSFHeader::LONG_INT_SIZE, 0); 234 | TagLib::ByteVector fileSize_v; 235 | 236 | DSFFile::FilePrivate::uint64ToVector(d->ID3v2Location, fileSize_v); 237 | insert(fileSize_v, 12, DSFHeader::LONG_INT_SIZE); // new file size 238 | insert(nulls_v, 20, DSFHeader::LONG_INT_SIZE); // set metadata offset to 0 239 | removeBlock(d->ID3v2Location, d->ID3v2OriginalSize); 240 | 241 | // Reset header info 242 | d->ID3v2OriginalSize = 0; 243 | d->fileSize = d->ID3v2Location; 244 | d->ID3v2Location = 0; 245 | d->hasID3v2 = false; 246 | } 247 | 248 | // Reinitialize properties because DSD header may have been changed 249 | delete d->properties; 250 | d->properties = new DSFProperties(this, 251 | TagLib::AudioProperties::Average); 252 | 253 | return success; 254 | } 255 | 256 | TagLib::ID3v2::Tag *DSFFile::ID3v2Tag() const 257 | { 258 | return d->tag; 259 | } 260 | 261 | void DSFFile::setID3v2FrameFactory(const TagLib::ID3v2::FrameFactory *factory) 262 | { 263 | d->ID3v2FrameFactory = factory; 264 | } 265 | 266 | bool DSFFile::hasID3v2Tag() const 267 | { 268 | return d->hasID3v2; 269 | } 270 | 271 | //////////////////////////////////////////////////////////////////////////////// 272 | // private members 273 | //////////////////////////////////////////////////////////////////////////////// 274 | 275 | bool DSFFile::secondSynchByte(char byte) 276 | { 277 | std::bitset<8> b(byte); 278 | 279 | // check to see if the byte matches 111xxxxx 280 | return b.test(7) && b.test(6) && b.test(5); 281 | } 282 | 283 | void DSFFile::read(bool readProperties, 284 | TagLib::AudioProperties::ReadStyle propertiesStyle) 285 | { 286 | if(readProperties) 287 | d->properties = new DSFProperties(this, propertiesStyle); 288 | 289 | d->ID3v2Location = d->properties->ID3v2Offset(); 290 | d->fileSize = d->properties->fileSize(); 291 | 292 | if(d->ID3v2Location > 0) { 293 | d->tag = new TagLib::ID3v2::Tag(this, d->ID3v2Location, d->ID3v2FrameFactory); 294 | d->ID3v2OriginalSize = d->tag->header()->completeTagSize(); 295 | 296 | if(d->tag->header()->tagSize() > 0) 297 | d->hasID3v2 = true; 298 | } else { 299 | // No ID3v2 Tag found, create an empty object. 300 | d->tag = new TagLib::ID3v2::Tag(); 301 | } 302 | } 303 | -------------------------------------------------------------------------------- /src/dsffile.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | copyright : (C) 2014 by Peking Duck Labs 3 | email : pekingducklabs@gmail.com 4 | ***************************************************************************/ 5 | 6 | /*************************************************************************** 7 | * This library is free software; you can redistribute it and/or modify * 8 | * it under the terms of the GNU Lesser General Public License version * 9 | * 2.1 as published by the Free Software Foundation. * 10 | * * 11 | * This library is distributed in the hope that it will be useful, but * 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of * 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 14 | * Lesser General Public License for more details. * 15 | * * 16 | * You should have received a copy of the GNU Lesser General Public * 17 | * License along with this library; if not, write to the Free Software * 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 19 | * 02110-1301 USA * 20 | ***************************************************************************/ 21 | 22 | #ifndef TAGLIB_DSFFILE_H 23 | #define TAGLIB_DSFFILE_H 24 | 25 | #include 26 | #include 27 | 28 | #include "dsfproperties.h" 29 | 30 | 31 | //! An implementation of TagLib::File with DSF (DSD) specific methods 32 | 33 | 34 | //! An DSF file class with some useful methods specific to DSF 35 | 36 | /*! 37 | * This implements the generic TagLib::File API and additionally provides 38 | * access to properties that are distinct to DSF files, notably access 39 | * to the different ID3 tags. 40 | */ 41 | 42 | namespace TagLib { namespace ID3v2 { class Tag; class FrameFactory; } } 43 | 44 | class DSFFile : public TagLib::File 45 | { 46 | public: 47 | /*! 48 | * Constructs an DSF file from \a file. If \a readProperties is true the 49 | * file's audio properties will also be read. 50 | * 51 | * \note In the current implementation, \a propertiesStyle is ignored. 52 | * 53 | * \deprecated This constructor will be dropped in favor of the one below 54 | * in a future version. 55 | */ 56 | DSFFile(TagLib::FileName file, bool readProperties = true, 57 | TagLib::AudioProperties::ReadStyle propertiesStyle 58 | = TagLib::AudioProperties::Average); 59 | 60 | /*! 61 | * Average an DSF file from \a file. If \a readProperties is true the 62 | * file's audio properties will also be read. 63 | * 64 | * If this file contains and ID3v2 tag the frames will be created using 65 | * \a frameFactory. 66 | * 67 | * \note In the current implementation, \a propertiesStyle is ignored. 68 | */ 69 | // BIC: merge with the above constructor 70 | DSFFile(TagLib::FileName file, TagLib::ID3v2::FrameFactory *frameFactory, 71 | bool readProperties = true, 72 | TagLib::AudioProperties::ReadStyle propertiesStyle 73 | = TagLib::AudioProperties::Average); 74 | 75 | /*! 76 | * Constructs an DSF file from \a stream. If \a readProperties is true the 77 | * file's audio properties will also be read. 78 | * 79 | * \note TagLib will *not* take ownership of the stream, the caller is 80 | * responsible for deleting it after the File object. 81 | * 82 | * If this file contains and ID3v2 tag the frames will be created using 83 | * \a frameFactory. 84 | * 85 | * \note In the current implementation, \a propertiesStyle is ignored. 86 | */ 87 | DSFFile(TagLib::IOStream *stream, TagLib::ID3v2::FrameFactory *frameFactory, 88 | bool readProperties = true, 89 | TagLib::AudioProperties::ReadStyle propertiesStyle = 90 | TagLib::AudioProperties::Average); 91 | 92 | /*! 93 | * Destroys this instance of the File. 94 | */ 95 | virtual ~DSFFile(); 96 | 97 | /*! 98 | * Returns a pointer to a ID3v2 tag 99 | */ 100 | virtual TagLib::Tag *tag() const; 101 | 102 | /*! 103 | * Implements the reading part of the unified property interface. 104 | */ 105 | TagLib::PropertyMap properties() const; 106 | 107 | // NEEDED?? 108 | void removeUnsupportedProperties(const TagLib::StringList &properties); 109 | 110 | /*! 111 | * Implements the writing part of the unified tag dictionary interface. 112 | * In order to avoid problems with deprecated tag formats, this method 113 | * always creates an ID3v2 tag if necessary. 114 | * If an ID3v1 tag exists, it will be updated as well, within the 115 | * limitations of that format. 116 | * The returned PropertyMap refers to the ID3v2 tag only. 117 | */ 118 | TagLib::PropertyMap setProperties(const TagLib::PropertyMap &); 119 | 120 | /*! 121 | * Returns the DSF::Properties for this file. If no audio properties 122 | * were read then this will return a null pointer. 123 | */ 124 | virtual TagLib::AudioProperties *audioProperties() const; 125 | 126 | /*! 127 | * Save the file. If at least one tag -- ID3v1 or ID3v2 -- exists this 128 | * will duplicate its content into the other tag. This returns true 129 | * if saving was successful. 130 | * 131 | * If neither exists or if both tags are empty, this will strip the tags 132 | * from the file. 133 | * 134 | * This is the same as calling save(AllTags); 135 | * 136 | * If you would like more granular control over the content of the tags, 137 | * with the concession of generality, use paramaterized save call below. 138 | * 139 | * \see save(int tags) 140 | */ 141 | virtual bool save(); 142 | 143 | /*! 144 | * Save the file. If at least one tag -- ID3v1 or ID3v2 -- exists this 145 | * will duplicate its content into the other tag. This returns true 146 | * if saving was successful. 147 | * 148 | * If neither exists or if both tags are empty, this will strip the tags 149 | * from the file. 150 | * 151 | * This is the same as calling save(AllTags); 152 | * 153 | * If you would like more granular control over the content of the tags, 154 | * with the concession of generality, use paramaterized save call below. 155 | * 156 | * ID3v2Version can be either 4 or 3. 157 | */ 158 | virtual bool save(int id3v2Version, bool shrink = true); 159 | 160 | /*! 161 | * Returns a pointer to the ID3v2 tag of the file. 162 | * 163 | * If \a create is false (the default) this may return a null pointer 164 | * if there is no valid ID3v2 tag. If \a create is true it will create 165 | * an ID3v2 tag if one does not exist and returns a valid pointer. 166 | * 167 | * \note This may return a valid pointer regardless of whether or not the 168 | * file on disk has an ID3v2 tag. Use hasID3v2Tag() to check if the file 169 | * on disk actually has an ID3v2 tag. 170 | * 171 | * \note The Tag is still owned by the DSF::File and should not be 172 | * deleted by the user. It will be deleted when the file (object) is 173 | * destroyed. 174 | * 175 | * \see hasID3v2Tag() 176 | */ 177 | TagLib::ID3v2::Tag *ID3v2Tag() const; 178 | 179 | 180 | /*! 181 | * This will strip the tags that match the OR-ed together TagTypes from the 182 | * file. By default it strips all tags. It returns true if the tags are 183 | * successfully stripped. 184 | * 185 | * This is equivalent to strip(tags, true) 186 | * 187 | * If \a freeMemory is true the ID3 and APE tags will be deleted and 188 | * pointers to them will be invalidated. 189 | */ 190 | //bool strip(bool freeMemory); 191 | 192 | /*! 193 | * Set the ID3v2::FrameFactory to something other than the default. 194 | * 195 | * \see ID3v2FrameFactory 196 | */ 197 | void setID3v2FrameFactory(const TagLib::ID3v2::FrameFactory *factory); 198 | 199 | /* 200 | * Returns the position in the file of the first frame. 201 | */ 202 | //long firstFrameOffset(); 203 | 204 | /* 205 | * Returns the position in the file of the next frame, 206 | * using the current position as start 207 | */ 208 | //long nextFrameOffset(long position); 209 | 210 | /* 211 | * Returns the position in the file of the previous frame, 212 | * using the current position as start 213 | */ 214 | //long previousFrameOffset(long position); 215 | 216 | /* 217 | * Returns the position in the file of the last DSF frame. 218 | */ 219 | //long lastFrameOffset(); 220 | 221 | 222 | /*! 223 | * Returns whether or not the file on disk actually has an ID3v2 tag. 224 | * 225 | * \see ID3v2Tag() 226 | */ 227 | bool hasID3v2Tag() const; 228 | 229 | private: 230 | DSFFile(const DSFFile &); 231 | DSFFile &operator=(const DSFFile &); 232 | 233 | // Read the actual audio file for tags 234 | void read(bool readProperties, 235 | TagLib::AudioProperties::ReadStyle propertiesStyle); 236 | 237 | /*! 238 | * ID3V2 frames can be recognized by the bit pattern 11111111 111, so the 239 | * first byte is easy to check for, however checking to see if the second 240 | * byte starts with \e 111 is a bit more tricky, hence this member function. 241 | */ 242 | static bool secondSynchByte(char byte); 243 | 244 | class FilePrivate; 245 | FilePrivate *d; 246 | }; 247 | 248 | #endif 249 | -------------------------------------------------------------------------------- /src/dsfheader.cpp: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | copyright : (C) 2014 by Peking Duck Labs 3 | email : pekingducklabs@gmail.com 4 | ***************************************************************************/ 5 | 6 | /*************************************************************************** 7 | * This library is free software; you can redistribute it and/or modify * 8 | * it under the terms of the GNU Lesser General Public License version * 9 | * 2.1 as published by the Free Software Foundation. * 10 | * * 11 | * This library is distributed in the hope that it will be useful, but * 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of * 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 14 | * Lesser General Public License for more details. * 15 | * * 16 | * You should have received a copy of the GNU Lesser General Public * 17 | * License along with this library; if not, write to the Free Software * 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 19 | * 02110-1301 USA * 20 | ***************************************************************************/ 21 | 22 | #include 23 | 24 | #include 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | #include "dsfheader.h" 31 | 32 | class DSFHeader::HeaderPrivate : public TagLib::RefCounter 33 | { 34 | public: 35 | HeaderPrivate() : 36 | isValid(false), 37 | version(Version1), 38 | sampleCount(0), 39 | channelType(Stereo), 40 | channelNum(2), 41 | sampleRate(0), 42 | bitsPerSample(0), 43 | ID3v2Offset(0), 44 | fileSize(0) 45 | {} 46 | 47 | bool isValid; 48 | Version version; // format version 49 | uint64_t sampleCount; 50 | ChannelType channelType; 51 | unsigned short channelNum; 52 | unsigned int sampleRate; 53 | unsigned short bitsPerSample; 54 | uint64_t ID3v2Offset; 55 | uint64_t fileSize; 56 | }; 57 | 58 | //////////////////////////////////////////////////////////////////////////////// 59 | // public members 60 | //////////////////////////////////////////////////////////////////////////////// 61 | 62 | DSFHeader::DSFHeader(const TagLib::ByteVector &data) 63 | { 64 | d = new HeaderPrivate; 65 | parse(data); 66 | } 67 | 68 | DSFHeader::DSFHeader(const DSFHeader &h) : d(h.d) 69 | { 70 | d->ref(); 71 | } 72 | 73 | DSFHeader::~DSFHeader() 74 | { 75 | if (d->deref()) 76 | delete d; 77 | } 78 | 79 | bool DSFHeader::isValid() const 80 | { 81 | return d->isValid; 82 | } 83 | 84 | DSFHeader::Version DSFHeader::version() const 85 | { 86 | return d->version; 87 | } 88 | 89 | unsigned int DSFHeader::sampleRate() const 90 | { 91 | return d->sampleRate; 92 | } 93 | 94 | DSFHeader::ChannelType DSFHeader::channelType() const 95 | { 96 | return d->channelType; 97 | } 98 | 99 | unsigned short DSFHeader::channelNum() const 100 | { 101 | return d->channelNum; 102 | } 103 | 104 | uint64_t DSFHeader::sampleCount() const 105 | { 106 | return d->sampleCount; 107 | } 108 | 109 | uint64_t DSFHeader::ID3v2Offset() const 110 | { 111 | return d->ID3v2Offset; 112 | } 113 | 114 | uint64_t DSFHeader::fileSize() const 115 | { 116 | return d->fileSize; 117 | } 118 | 119 | unsigned short DSFHeader::bitsPerSample() const 120 | { 121 | return d->bitsPerSample; 122 | } 123 | 124 | DSFHeader &DSFHeader::operator=(const DSFHeader &h) 125 | { 126 | if(&h == this) 127 | return *this; 128 | 129 | if(d->deref()) 130 | delete d; 131 | 132 | d = h.d; 133 | d->ref(); 134 | return *this; 135 | } 136 | 137 | //////////////////////////////////////////////////////////////////////////////// 138 | // private members 139 | //////////////////////////////////////////////////////////////////////////////// 140 | 141 | void DSFHeader::parse(const TagLib::ByteVector &data) 142 | { 143 | if (data.size() < DSD_HEADER_SIZE + FMT_HEADER_SIZE) { 144 | std::cerr <<"DSFHeader::parse(): header size incorrect" << std::endl; 145 | return; 146 | } 147 | 148 | const char *hdr = data.data(); 149 | size_t offset = 0; 150 | 151 | // 152 | // ******** DSD chunk header ******** 153 | // DSD header chunk should start with "DSD ". 154 | // 155 | if (hdr[0] != 'D' || hdr[1] != 'S' || hdr[2] != 'D' || hdr[3] != ' ') 156 | { 157 | std::cerr <<"DSD::Header::parse(): DSD header's first 4 bytes != 'DSD '" << std::endl; 158 | return; 159 | } 160 | offset += 4; 161 | 162 | // The next 8 bytes contain the size of DSD header 163 | // (numerical data is stored in little endian) 164 | if (data.toLongLong(offset, false) != DSD_HEADER_SIZE) 165 | { 166 | std::cerr <<"DSD::Header::parse(): DSD header size is incorrect" << std::endl; 167 | return; 168 | } 169 | offset += LONG_INT_SIZE; 170 | 171 | // The next 8 bytes contains the file size 172 | d->fileSize = bytesToUInt64(&hdr[0], offset); 173 | offset += LONG_INT_SIZE; 174 | 175 | // The next 8 bytes contains the offset to id3v2 tag (0 if not exists) 176 | d->ID3v2Offset = bytesToUInt64(&hdr[0], offset); 177 | offset += LONG_INT_SIZE; 178 | 179 | // 180 | // ********* FMT chunk ******** 181 | // 182 | // FMT header chunk should start with "fmt ". 183 | // 184 | if (hdr[offset] != 'f' || hdr[offset + 1] != 'm' || 185 | hdr[offset + 2] != 't' || hdr[offset + 3] != ' ') 186 | { 187 | std::cerr <<"DSD::Header::parse(): FMT header's first 4 bytes != 'fmt '" << std::endl; 188 | return; 189 | } 190 | offset += 4; 191 | 192 | // The next 8 bytes contain the size of FMT header, which should be 52 193 | if (data.toLongLong(offset, false) != FMT_HEADER_SIZE) 194 | { 195 | std::cerr <<"DSD::Header::parse(): FMT header size is incorrect" << std::endl; 196 | return; 197 | } 198 | offset += LONG_INT_SIZE; 199 | 200 | // Format version 201 | // There's only version 1 for now... 202 | unsigned int ver = data.toUInt(offset, false); 203 | if (ver != 1) { 204 | std::cerr <<"DSD::Header::parse(): format version != 1" << std::endl; 205 | return; 206 | } 207 | d->version = static_cast(ver); 208 | offset += INT_SIZE; 209 | 210 | // Format ID 211 | if (data.toUInt(offset, false) != 0) { 212 | std::cerr <<"DSD::Header::parse(): format ID != 0" << std::endl; 213 | return; 214 | } 215 | offset += INT_SIZE; 216 | 217 | // Channel Type 218 | unsigned int ct = data.toUInt(offset, false); 219 | if (ct < 1 || ct > 7) { 220 | std::cerr <<"DSD::Header::parse(): channel type out of range" << std::endl; 221 | return; 222 | } 223 | d->channelType = static_cast(ct); 224 | offset += INT_SIZE; 225 | 226 | // Channel Num 227 | d->channelNum = data.toUInt(offset, false); 228 | if (d->channelNum < MinType || d->channelNum > MaxType) { 229 | std::cerr <<"DSD::Header::parse(): channel num out of range" << std::endl; 230 | return; 231 | } 232 | offset += INT_SIZE; 233 | 234 | // Sampling frequency 235 | d->sampleRate = data.toUInt(offset, false); 236 | if (d->sampleRate != 2822400 && d->sampleRate != 5644800) { 237 | std::cerr <<"DSD::Header::parse(): invalid sampling frequency" << std::endl; 238 | return; 239 | } 240 | offset += INT_SIZE; 241 | 242 | // Bits per sample 243 | d->bitsPerSample = data.toUInt(offset, false); 244 | if (d->bitsPerSample != 1 && d->bitsPerSample != 8) { 245 | std::cerr <<"DSD::Header::parse(): bits per sample invalid" << std::endl; 246 | return; 247 | } 248 | offset += INT_SIZE; 249 | 250 | // Sample count 251 | d->sampleCount = bytesToUInt64(&hdr[0], offset); 252 | offset += LONG_INT_SIZE; 253 | 254 | // Block size per channel 255 | if (data.toUInt(offset, false) != 4096) { 256 | std::cerr <<"DSD::Header::parse(): block size != 4096" << std::endl; 257 | return; 258 | } 259 | //offset += 4; 260 | 261 | // Reserved 262 | // offset += 4; 263 | 264 | d->isValid = true; 265 | } 266 | -------------------------------------------------------------------------------- /src/dsfheader.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | copyright : (C) 2014 by Peking Duck Labs 3 | email : pekingducklabs@gmail.com 4 | ***************************************************************************/ 5 | 6 | /*************************************************************************** 7 | * This library is free software; you can redistribute it and/or modify * 8 | * it under the terms of the GNU Lesser General Public License version * 9 | * 2.1 as published by the Free Software Foundation. * 10 | * * 11 | * This library is distributed in the hope that it will be useful, but * 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of * 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 14 | * Lesser General Public License for more details. * 15 | * * 16 | * You should have received a copy of the GNU Lesser General Public * 17 | * License along with this library; if not, write to the Free Software * 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 19 | * 02110-1301 USA * 20 | ***************************************************************************/ 21 | 22 | #ifndef TAGLIB_DSFHEADER_H 23 | #define TAGLIB_DSFHEADER_H 24 | 25 | //#include 26 | 27 | //! An implementation of DSF header 28 | 29 | /*! 30 | * This is an implementation of DSF header. Check out 31 | * this 32 | * document as a reference. 33 | */ 34 | 35 | #include 36 | 37 | class DSFHeader 38 | { 39 | public: 40 | static const int DSD_HEADER_SIZE = 28; 41 | static const int FMT_HEADER_SIZE = 52; 42 | static const int LONG_INT_SIZE = 8; // width of a long integer 43 | static const int INT_SIZE = 4; // width of an integer 44 | 45 | /*! 46 | * Parses an DSF header based on \a data. 47 | */ 48 | DSFHeader(const TagLib::ByteVector &data); 49 | 50 | /*! 51 | * Does a shallow copy of \a h. 52 | */ 53 | DSFHeader(const DSFHeader &h); 54 | 55 | /*! 56 | * Destroys this Header instance. 57 | */ 58 | virtual ~DSFHeader(); 59 | 60 | /*! 61 | * Returns true if header has legal values. 62 | */ 63 | bool isValid() const; 64 | 65 | /*! 66 | * The DSD file format version 67 | */ 68 | enum Version { 69 | //! DSD Version 1 70 | Version1 = 1 71 | }; 72 | 73 | /*! 74 | * Channel Type: 75 | */ 76 | enum ChannelType { 77 | MinType = 0, 78 | 79 | //! 1: mono 80 | Mono = 1, 81 | //! 2: stereo (front left, front right) 82 | Stereo = 2, 83 | //! 3: 3 channels (front left, front right, center) 84 | ThreeChannels = 3, 85 | //! 4: quad (front left/right, back left/right) 86 | Quad = 4, 87 | //! 5: 4 channels (front left, front right, low frequency, center) 88 | FourChannels = 5, 89 | //! 6: 5 channels (front left/right, back left/right, center) 90 | FiveChannels = 6, 91 | //! 7: 5.1 channels (front left/right, back left/right, center, low freq.) 92 | FiveOneChannels = 7, 93 | 94 | MaxType = 8 95 | }; 96 | 97 | /*! 98 | * Returns the DSD Version of the header. 99 | */ 100 | Version version() const; 101 | 102 | /*! 103 | * Returns the Channel Type of the header 104 | */ 105 | ChannelType channelType() const; 106 | 107 | /*! 108 | * Returns the Channel Num of the header 109 | */ 110 | unsigned short channelNum() const; 111 | 112 | /*! 113 | * Returns the sample rate in Hz. 114 | */ 115 | unsigned int sampleRate() const; 116 | 117 | /*! 118 | * Returns the sample count 119 | */ 120 | uint64_t sampleCount() const; 121 | 122 | /*! 123 | * Returns the bits per sample 124 | */ 125 | unsigned short bitsPerSample() const; 126 | 127 | /*! 128 | * Returns the offset to the metadata block 129 | */ 130 | uint64_t ID3v2Offset() const; 131 | 132 | /*! 133 | * Returns the file size 134 | */ 135 | uint64_t fileSize() const; 136 | 137 | /*! 138 | * Makes a shallow copy of the header. 139 | */ 140 | DSFHeader &operator=(const DSFHeader &h); 141 | 142 | // Assume LSB comes first 143 | inline uint64_t bytesToUInt64(const char *v, uint64_t offset = 0) { 144 | uint64_t res = 0; 145 | for (int i = 0; i < LONG_INT_SIZE; i++) { 146 | res |= static_cast(static_cast(v[offset + i])) 147 | << (i * 8); 148 | } 149 | return res; 150 | } 151 | private: 152 | void parse(const TagLib::ByteVector &data); 153 | 154 | class HeaderPrivate; 155 | HeaderPrivate *d; 156 | }; 157 | 158 | 159 | #endif 160 | -------------------------------------------------------------------------------- /src/dsfproperties.cpp: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | copyright : (C) 2014 by Peking Duck Labs 3 | email : pekingducklabs@gmail.com 4 | ***************************************************************************/ 5 | 6 | /*************************************************************************** 7 | * This library is free software; you can redistribute it and/or modify * 8 | * it under the terms of the GNU Lesser General Public License version * 9 | * 2.1 as published by the Free Software Foundation. * 10 | * * 11 | * This library is distributed in the hope that it will be useful, but * 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of * 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 14 | * Lesser General Public License for more details. * 15 | * * 16 | * You should have received a copy of the GNU Lesser General Public * 17 | * License along with this library; if not, write to the Free Software * 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 19 | * 02110-1301 USA * 20 | ***************************************************************************/ 21 | 22 | #include 23 | 24 | #include 25 | 26 | #include "dsfproperties.h" 27 | #include "dsffile.h" 28 | 29 | class DSFProperties::PropertiesPrivate 30 | { 31 | public: 32 | PropertiesPrivate(DSFFile *f, ReadStyle s) : 33 | file(f), 34 | style(s), 35 | length(0), 36 | bitrate(0), 37 | sampleRate(0), 38 | channels(0), 39 | ID3v2Offset(0), 40 | sampleCount(0), 41 | fileSize(0), 42 | bitsPerSample(1), 43 | version(DSFHeader::Version1), 44 | channelType(DSFHeader::Stereo) 45 | {} 46 | 47 | DSFFile *file; 48 | TagLib::AudioProperties::ReadStyle style; 49 | int length; 50 | int bitrate; 51 | int sampleRate; 52 | int channels; 53 | uint64_t ID3v2Offset; 54 | uint64_t sampleCount; 55 | uint64_t fileSize; 56 | int bitsPerSample; 57 | DSFHeader::Version version; 58 | DSFHeader::ChannelType channelType; 59 | }; 60 | 61 | //////////////////////////////////////////////////////////////////////////////// 62 | // public members 63 | //////////////////////////////////////////////////////////////////////////////// 64 | 65 | DSFProperties::DSFProperties(DSFFile *file, 66 | TagLib::AudioProperties::ReadStyle style) 67 | : TagLib::AudioProperties(style) 68 | { 69 | d = new PropertiesPrivate(file, style); 70 | 71 | if(file && file->isOpen()) 72 | read(); 73 | } 74 | 75 | DSFProperties::~DSFProperties() 76 | { 77 | delete d; 78 | } 79 | 80 | int DSFProperties::length() const 81 | { 82 | return d->sampleCount / d->sampleRate; 83 | } 84 | 85 | int DSFProperties::bitrate() const 86 | { 87 | return d->sampleRate * d->bitsPerSample / 1024; 88 | } 89 | 90 | int DSFProperties::sampleRate() const 91 | { 92 | return d->sampleRate; 93 | } 94 | 95 | int DSFProperties::channels() const 96 | { 97 | return d->channels; 98 | } 99 | 100 | DSFHeader::Version DSFProperties::version() const 101 | { 102 | return d->version; 103 | } 104 | 105 | DSFHeader::ChannelType DSFProperties::channelType() const 106 | { 107 | return d->channelType; 108 | } 109 | 110 | uint64_t DSFProperties::ID3v2Offset() const 111 | { 112 | return d->ID3v2Offset; 113 | } 114 | 115 | uint64_t DSFProperties::fileSize() const 116 | { 117 | return d->fileSize; 118 | } 119 | 120 | uint64_t DSFProperties::sampleCount() const 121 | { 122 | return d->sampleCount; 123 | } 124 | 125 | int DSFProperties::bitsPerSample() const 126 | { 127 | return d->bitsPerSample; 128 | } 129 | 130 | //////////////////////////////////////////////////////////////////////////////// 131 | // private members 132 | //////////////////////////////////////////////////////////////////////////////// 133 | 134 | void DSFProperties::read() 135 | { 136 | // Go to the beginning of the file 137 | d->file->seek(0); 138 | 139 | DSFHeader h(d->file->readBlock(DSFHeader::DSD_HEADER_SIZE + 140 | DSFHeader::FMT_HEADER_SIZE)); 141 | 142 | if (!h.isValid()) { 143 | std::cerr << "DSFProperties::read(): file header is not valid" << std::endl; 144 | return; 145 | } 146 | 147 | d->sampleRate = h.sampleRate(); 148 | d->sampleCount = h.sampleCount(); 149 | d->bitsPerSample = h.bitsPerSample(); 150 | d->channels = h.channelNum(); 151 | d->version = h.version(); 152 | d->fileSize = h.fileSize(); 153 | d->channelType = h.channelType(); 154 | d->ID3v2Offset = h.ID3v2Offset(); 155 | } 156 | -------------------------------------------------------------------------------- /src/dsfproperties.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | copyright : (C) 2014 by Peking Duck Labs 3 | email : pekingducklabs@gmail.com 4 | ***************************************************************************/ 5 | 6 | /*************************************************************************** 7 | * This library is free software; you can redistribute it and/or modify * 8 | * it under the terms of the GNU Lesser General Public License version * 9 | * 2.1 as published by the Free Software Foundation. * 10 | * * 11 | * This library is distributed in the hope that it will be useful, but * 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of * 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 14 | * Lesser General Public License for more details. * 15 | * * 16 | * You should have received a copy of the GNU Lesser General Public * 17 | * License along with this library; if not, write to the Free Software * 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 19 | * 02110-1301 USA * 20 | ***************************************************************************/ 21 | 22 | #ifndef TAGLIB_DSFPROPERTIES_H 23 | #define TAGLIB_DSFPROPERTIES_H 24 | 25 | #include 26 | 27 | #include "dsfheader.h" 28 | 29 | 30 | class DSFFile; 31 | 32 | //! An implementation of audio property reading for DSF 33 | 34 | /*! 35 | * This reads the data from a DSF stream found in the 36 | * AudioProperties API. 37 | */ 38 | 39 | class DSFProperties : public TagLib::AudioProperties 40 | { 41 | public: 42 | /*! 43 | * Create an instance of DSF::Properties with the data read from the 44 | * DSF::File \a file. 45 | */ 46 | DSFProperties(DSFFile *file, 47 | TagLib::AudioProperties::ReadStyle style = Average); 48 | 49 | /*! 50 | * Destroys this DSF Properties instance. 51 | */ 52 | virtual ~DSFProperties(); 53 | 54 | // Reimplementations. 55 | 56 | virtual int length() const; 57 | virtual int bitrate() const; 58 | virtual int sampleRate() const; 59 | virtual int channels() const; 60 | 61 | /*! 62 | * Returns the DSF Version of the file. 63 | */ 64 | DSFHeader::Version version() const; 65 | 66 | /*! 67 | * Returns the channel type 68 | */ 69 | DSFHeader::ChannelType channelType() const; 70 | 71 | /*! 72 | * Returns the ID3v2 offset in the file 73 | */ 74 | uint64_t ID3v2Offset() const; 75 | 76 | /*! 77 | * Returns the file size 78 | */ 79 | uint64_t fileSize() const; 80 | 81 | /*! 82 | * Returns the sample count 83 | */ 84 | uint64_t sampleCount() const; 85 | 86 | /*! 87 | * Returns the bits per sample 88 | */ 89 | int bitsPerSample() const; 90 | 91 | private: 92 | DSFProperties(const DSFProperties &); 93 | DSFProperties &operator=(const DSFProperties &); 94 | 95 | void read(); 96 | 97 | class PropertiesPrivate; 98 | PropertiesPrivate *d; 99 | }; 100 | 101 | #endif 102 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | copyright : (C) 2014 by Peking Duck Labs 3 | email : pekingducklabs@gmail.com 4 | ***************************************************************************/ 5 | 6 | /*************************************************************************** 7 | * This library is free software; you can redistribute it and/or modify * 8 | * it under the terms of the GNU Lesser General Public License version * 9 | * 2.1 as published by the Free Software Foundation. * 10 | * * 11 | * This library is distributed in the hope that it will be useful, but * 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of * 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 14 | * Lesser General Public License for more details. * 15 | * * 16 | * You should have received a copy of the GNU Lesser General Public * 17 | * License along with this library; if not, write to the Free Software * 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 19 | * 02110-1301 USA * 20 | ***************************************************************************/ 21 | 22 | #include 23 | #include "metadsf.h" 24 | #include "utils.h" 25 | #include "options.h" 26 | 27 | typedef std::tuple PicTuple; 30 | typedef std::list PicTupleList; 31 | 32 | bool doDelete(MetaDSF &, OptionObj &); 33 | bool doAdd(MetaDSF &, OptionObj &); 34 | bool validatePictures(OptionObj &, PicTupleList &); 35 | bool importPictures(MetaDSF &, PicTupleList &); 36 | 37 | void displayVersion() { 38 | std::cout << PROG << " version " << VERSION << std::endl; 39 | } 40 | 41 | int main(int argc, char *argv[]) 42 | { 43 | // Command line parsing using a wrapper around 44 | // "The Lean Mean C++ Option Parser" 45 | // http://optionparser.sourceforge.net/ 46 | OptionObj opt; 47 | if (!opt.parse(argc - 1, argv + 1)) { 48 | return 1; 49 | } 50 | 51 | if (opt.showHelp) { 52 | displayVersion(); 53 | opt.printUsage(); 54 | return 0; 55 | } 56 | 57 | if (opt.showVersion) { 58 | displayVersion(); 59 | return 0; 60 | } 61 | 62 | // Validate encoding if supplied 63 | if (!opt.encoding.isEmpty() && !MetaDSF::isValidEncoding(opt.encoding)) { 64 | std::cerr << "Invalid encoding: " << opt.encoding << std::endl; 65 | return 1; 66 | } 67 | 68 | // Validate version if supplied 69 | if (!opt.version.isEmpty() && opt.version.toInt() != 3 && 70 | opt.version.toInt() != 4) 71 | { 72 | std::cerr << "Invalid ID3v2 version: " << opt.version << std::endl; 73 | return 1; 74 | } 75 | 76 | 77 | // Load tag data from files 78 | StringMap tmp; 79 | if (!opt.setTagsFile.isEmpty()) { 80 | if (!readPairsFromFile(opt.setTagsFile.toCString(), tmp)) 81 | return 1; 82 | if (!opt.removeEverything) 83 | for (auto &p: tmp) 84 | opt.removeTagList.push_back(p.first); 85 | opt.addTagMap.insert(tmp.begin(), tmp.end()); 86 | } 87 | 88 | if (!opt.addTagsFile.isEmpty()) 89 | if (!readPairsFromFile(opt.addTagsFile.toCString(), opt.addTagMap)) 90 | return 1; 91 | 92 | // Validate keys - only for addMap 93 | // for (auto &p : opt.addTagMap) 94 | // if (!MetaDSF::isValidFrameID(p.first)) { 95 | // std::cerr << "Tag '" << p.first; 96 | // std::cerr <<"' invalid or unsupported" << std::endl; 97 | // return 1; 98 | // } 99 | 100 | // Validate the types of the pictures to be deleted 101 | for (auto &p : opt.removePicList) { 102 | long t; 103 | if (!stringToLong(p.toCString(), t) || !MetaDSF::isValidPicType(t)) { 104 | std::cerr << "Picture type '" << p << "' invalid'" << std::endl; 105 | return 1; 106 | } 107 | } 108 | 109 | // Validate pictures to be imported 110 | // Check if the files really exist, are readable and of supported extensions 111 | // (jpeg, tiff, gif...) 112 | // Check if types are correct 113 | PicTupleList picTupleList; 114 | if (!validatePictures(opt, picTupleList)) { 115 | return 1; 116 | } 117 | 118 | //if (opt.dryRun) { 119 | // opt.print(); 120 | //} 121 | 122 | for (auto &fileName : opt.fileList) { 123 | MetaDSF dsf(fileName.toCString()); 124 | 125 | if (!opt.encoding.isEmpty()) 126 | dsf.setEncoding(MetaDSF::getEncTypeByName(opt.encoding)); 127 | if (!opt.version.isEmpty()) 128 | dsf.setID3v2Version(opt.version.toInt()); 129 | 130 | if (!dsf.isOK()) { 131 | std::cerr << fileName << ": error reading file." << std::endl; 132 | continue; 133 | } 134 | if (!doDelete(dsf, opt)) { 135 | return 1; 136 | } 137 | if (!doAdd(dsf, opt)) { 138 | return 1; 139 | } 140 | if (!importPictures(dsf, picTupleList)) { 141 | return 1; 142 | } 143 | if (!opt.dryRun) 144 | dsf.save(); 145 | 146 | if (opt.exportPics) { 147 | std::string basename = 148 | std::string(fileName.toCString()).substr(0, fileName.rfind(".")); 149 | dsf.exportPictures(basename.c_str()); 150 | } 151 | std::string prefix = ""; 152 | if (opt.fileList.size() > 1) { 153 | prefix += fileName.toCString(); 154 | prefix += ":"; 155 | } 156 | 157 | if (opt.showInfo) 158 | dsf.printInfo(prefix.c_str()); 159 | 160 | if (opt.showTags) 161 | dsf.printTags(prefix.c_str()); 162 | } 163 | } // main() 164 | 165 | bool doDelete(MetaDSF &dsf, OptionObj &opt) { 166 | if (opt.removeEverything) { 167 | dsf.deleteAllTags(); 168 | } else { 169 | for (auto &i : opt.removeTagList) { 170 | dsf.deleteTags(i); 171 | } 172 | for (auto &i : opt.removePicList) { 173 | dsf.deletePictures(i); 174 | } 175 | } 176 | return true; 177 | } 178 | 179 | bool doAdd(MetaDSF &dsf, OptionObj &opt) { 180 | for (auto &i : opt.addTagMap) { 181 | TagLib::String name = MetaDSF::getFrameNameByID(i.first); 182 | 183 | //std::cerr << " set " << i.first << "(" << name << ") to "; 184 | //std::cerr << i.second << std::endl; 185 | dsf.setTag(name, i.second); 186 | } 187 | return true; 188 | } 189 | 190 | bool validatePictures(OptionObj &opt, PicTupleList &tupleList) { 191 | for (auto &p : opt.addPicList) { 192 | StringVector tmp; 193 | TagLib::ID3v2::AttachedPictureFrame::Type pt = 194 | TagLib::ID3v2::AttachedPictureFrame::FrontCover; 195 | TagLib::String comment; 196 | 197 | // parse picture specs 198 | // --import-picture=PATH|[type|comment] 199 | split(p.toCString(), "|", tmp, true, 3); 200 | 201 | // check extension 202 | if (!MetaDSF::isValidImage(tmp[0])) { 203 | std::cerr << "Unknown image format: " << tmp[0] << std::endl; 204 | return false; 205 | } 206 | 207 | if (!isReadableFile(tmp[0].toCString())) { 208 | std::cerr << tmp[0] << " not accessible" << std::endl; 209 | return false; 210 | } 211 | if (tmp.size() >= 2) { 212 | if (tmp[1].size() != 0) { // check if type is valid 213 | long t; 214 | if (!stringToLong(tmp[1].toCString(), t) || !MetaDSF::isValidPicType(t)) { 215 | std::cerr << "Picture type '" << tmp[1] << "' invalid'" << std::endl; 216 | return false; 217 | } 218 | pt = static_cast(t); 219 | } 220 | } 221 | if (tmp.size() == 3) 222 | comment = tmp[2]; 223 | 224 | tupleList.push_back(PicTuple(tmp[0], pt, comment)); 225 | } 226 | return true; 227 | } 228 | 229 | bool importPictures(MetaDSF &dsf, PicTupleList &pList) { 230 | for (auto &p : pList) { 231 | if (!dsf.attachPicture(std::get<0>(p), std::get<1>(p), std::get<2>(p))) 232 | return false; 233 | } 234 | return true; 235 | } 236 | -------------------------------------------------------------------------------- /src/metadsf.cpp: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | copyright : (C) 2014 by Peking Duck Labs 3 | email : pekingducklabs@gmail.com 4 | ***************************************************************************/ 5 | 6 | /*************************************************************************** 7 | * This library is free software; you can redistribute it and/or modify * 8 | * it under the terms of the GNU Lesser General Public License version * 9 | * 2.1 as published by the Free Software Foundation. * 10 | * * 11 | * This library is distributed in the hope that it will be useful, but * 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of * 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 14 | * Lesser General Public License for more details. * 15 | * * 16 | * You should have received a copy of the GNU Lesser General Public * 17 | * License along with this library; if not, write to the Free Software * 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 19 | * 02110-1301 USA * 20 | ***************************************************************************/ 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | #include 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #include "dsffile.h" 36 | #include "utils.h" 37 | #include "metadsf.h" 38 | 39 | //////////////////////////// IMPL ////////////////////////////// 40 | class MetaDSF::MetaDSFImpl { 41 | public: 42 | MetaDSFImpl(const char *path) : _changed(false), 43 | _file(path), 44 | _ID3v2_version(4), 45 | _encoding(TagLib::String::UTF8) 46 | {} 47 | ~MetaDSFImpl() {} 48 | 49 | /////////////// Utility Functions ////////////// 50 | 51 | // delete all frames in the list 52 | void deleteFrames(const TagLib::ID3v2::FrameList &); 53 | 54 | // dup list 55 | void dupFrameList(const TagLib::ID3v2::FrameList &src, 56 | TagLib::ID3v2::FrameList &dest); 57 | 58 | int deleteTags(const TagLib::String &); 59 | 60 | /////////////// Variables ////////////// 61 | bool _changed; // whether there's any change to metadata 62 | // save() uses this to determine whether to write to disk 63 | DSFFile _file; 64 | int _ID3v2_version; // What version of ID3v2 to save (3 or 4) 65 | TagLib::String::Type _encoding; // Text encoding 66 | }; 67 | 68 | ///////////////////////////// METADSF ////////////////////////// 69 | MetaDSF::MetaDSF(const char *path) 70 | { 71 | _i = new MetaDSFImpl(path); 72 | } 73 | 74 | MetaDSF::~MetaDSF() 75 | { 76 | //save(); 77 | if (_i) { 78 | delete _i; 79 | } 80 | } 81 | 82 | bool MetaDSF::save() 83 | { 84 | // only save when changed were made 85 | if (_i->_changed) { 86 | _i->_changed = false; 87 | return _i->_file.save(_i->_ID3v2_version, true); 88 | } 89 | return true; 90 | } 91 | 92 | bool MetaDSF::isOK() const 93 | { 94 | return (_i->_file.isOpen() && _i->_file.isValid()); 95 | } 96 | 97 | void MetaDSF::printInfo(const char *prefix) const 98 | { 99 | DSFProperties *p = static_cast 100 | (_i->_file.audioProperties()); 101 | 102 | if (p) { 103 | std::cout << prefix; 104 | std::cout << "DSD version=" << p->version() << std::endl; 105 | std::cout << prefix; 106 | std::cout << "Sample rate=" << p->sampleRate() << "Hz" << std::endl; 107 | std::cout << prefix; 108 | std::cout << "No. of channels=" << p->channels() << std::endl; 109 | std::cout << prefix; 110 | std::cout << "Channel type=" << channelTypeDesc[p->channelType()] << std::endl; 111 | std::cout << prefix; 112 | std::cout << "Length=" << p->length() << "s" << std::endl; 113 | std::cout << prefix; 114 | std::cout << "No. of samples=" << p->sampleCount() << std::endl; 115 | std::cout << prefix; 116 | std::cout << "Bits per sample=" << p->bitsPerSample() << std::endl; 117 | std::cout << prefix; 118 | std::cout << "Metadata offset=" << p->ID3v2Offset() << std::endl; 119 | std::cout << prefix; 120 | std::cout << "File size=" << p->fileSize() << std::endl; 121 | } 122 | 123 | // if (_i->_file.ID3v2Tag()->isEmpty()) { 124 | // std::cout << prefix; 125 | // std::cout << "No ID3v2 metadata found" << std::endl; 126 | // return; 127 | // } 128 | 129 | std::cout << prefix; 130 | std::cout << "ID3v2 version=2." 131 | << _i->_file.ID3v2Tag()->header()->majorVersion() 132 | << "." 133 | << _i->_file.ID3v2Tag()->header()->revisionNumber() 134 | << std::endl; 135 | std::cout << prefix; 136 | std::cout << "Tag size=" 137 | << _i->_file.ID3v2Tag()->header()->completeTagSize() 138 | << " bytes" << std::endl; 139 | } 140 | 141 | void MetaDSF::printTags(const char *prefix) const 142 | { 143 | if (_i->_file.ID3v2Tag()->isEmpty()) { 144 | return; 145 | } 146 | 147 | TagLib::ID3v2::FrameList l = _i->_file.ID3v2Tag()->frameList(); 148 | TagLib::ID3v2::FrameList::ConstIterator it; 149 | 150 | for (it = l.begin(); it != l.end(); it++) { 151 | std::cout << prefix; 152 | std::cout << (*it)->frameID() << "=" << (*it)->toString() << std::endl; 153 | } 154 | } 155 | 156 | int MetaDSF::setTag(const TagLib::String &key, const TagLib::String &val, 157 | bool replace) 158 | { 159 | TagLib::StringList vals; 160 | 161 | vals.append(val); 162 | return setTag(key, vals, replace); 163 | } 164 | 165 | int MetaDSF::setTag(const TagLib::String &key, 166 | const TagLib::StringList &sl, 167 | bool replace) 168 | { 169 | int nReplaced = 0; 170 | if (replace) 171 | nReplaced = _i->deleteTags(key); 172 | 173 | TagLib::ID3v2::Frame *f = TagLib::ID3v2::Frame::createTextualFrame(key, sl); 174 | _i->_file.ID3v2Tag()->addFrame(f); 175 | _i->_changed = true; 176 | return nReplaced; 177 | } 178 | 179 | int MetaDSF::setTagTXXX(const TagLib::String &desc, 180 | const TagLib::String &val, 181 | bool replace) 182 | { 183 | int nReplaced = 0; 184 | if (replace) 185 | nReplaced = _i->deleteTags("TXXX"); 186 | 187 | TagLib::ID3v2::UserTextIdentificationFrame *f = 188 | new TagLib::ID3v2::UserTextIdentificationFrame(TagLib::String(desc), 189 | TagLib::String(val), 190 | _i->_encoding); 191 | _i->_file.ID3v2Tag()->addFrame(f); 192 | _i->_changed = true; 193 | return nReplaced; 194 | } 195 | 196 | int MetaDSF::setTagTMCL(const TagLib::PropertyMap &m, bool replace) 197 | { 198 | int nReplaced = 0; 199 | if (replace) 200 | nReplaced = _i->deleteTags("TMCL"); 201 | 202 | TagLib::ID3v2::TextIdentificationFrame *f = 203 | TagLib::ID3v2::TextIdentificationFrame::createTMCLFrame(m); 204 | _i->_file.ID3v2Tag()->addFrame(f); 205 | _i->_changed = true; 206 | return nReplaced; 207 | } 208 | 209 | int MetaDSF::setTagWXXX(const TagLib::String &url, 210 | const TagLib::String &urlDesc, 211 | bool replace) 212 | { 213 | int nReplaced = 0; 214 | if (replace) 215 | nReplaced = _i->deleteTags("WXXX"); 216 | 217 | TagLib::ID3v2::UserUrlLinkFrame *f = 218 | new TagLib::ID3v2::UserUrlLinkFrame(_i->_encoding); 219 | f->setDescription(urlDesc); 220 | f->setUrl(url); 221 | _i->_file.ID3v2Tag()->addFrame(f); 222 | _i->_changed = true; 223 | return nReplaced; 224 | } 225 | 226 | int MetaDSF::setTagTIPL(const TagLib::PropertyMap &m, bool replace) 227 | { 228 | int nReplaced = 0; 229 | if (replace) 230 | nReplaced = _i->deleteTags("TIPL"); 231 | 232 | TagLib::ID3v2::TextIdentificationFrame *f = 233 | TagLib::ID3v2::TextIdentificationFrame::createTIPLFrame(m); 234 | _i->_file.ID3v2Tag()->addFrame(f); 235 | _i->_changed = true; 236 | return nReplaced; 237 | } 238 | 239 | 240 | // void MetaDSF::setTitle(const TagLib::String &val) { 241 | // _i->deleteTags("TIT2"); 242 | // _i->_file.ID3v2Tag()->setTitle(val); 243 | // } 244 | 245 | // void MetaDSF::setGenre(const TagLib::String &val) { 246 | // _i->deleteTags("TCON"); 247 | // _i->_file.ID3v2Tag()->setGenre(val); 248 | // } 249 | 250 | // void MetaDSF::setYear(unsigned int year) { 251 | // _i->deleteTags("TDRC"); 252 | // _i->_file.ID3v2Tag()->setYear(year); 253 | // } 254 | 255 | // void MetaDSF::setAlbum(const TagLib::String &val) { 256 | // _i->deleteTags("TALB"); 257 | // _i->_file.ID3v2Tag()->setAlbum(val); 258 | // } 259 | 260 | // void MetaDSF::setTrack(unsigned int track) { 261 | // _i->deleteTags("TRCK"); 262 | // _i->_file.ID3v2Tag()->setTrack(track); 263 | // } 264 | 265 | // void MetaDSF::setArtist(const TagLib::String &val) { 266 | // _i->deleteTags("TPE1"); 267 | // _i->_file.ID3v2Tag()->setArtist(val); 268 | // } 269 | 270 | int MetaDSF::deleteTags(const TagLib::String &key) 271 | { 272 | if (key.isEmpty()) { 273 | std::cerr << "deleteTags(): key is empty" << std::endl; 274 | return 0; 275 | } 276 | return _i->deleteTags(key); 277 | } 278 | 279 | int MetaDSF::deleteAllTags() { 280 | return _i->deleteTags(""); 281 | } 282 | 283 | 284 | bool MetaDSF::attachPicture(const TagLib::String &path, 285 | const TagLib::ID3v2::AttachedPictureFrame::Type t, 286 | const TagLib::String &comment) 287 | { 288 | // Determine MIME type 289 | TagLib::String mimeType; 290 | TagLib::String ext = path.substr(path.rfind(".") + 1); 291 | 292 | transform(ext.begin(), ext.end(), ext.begin(), ::tolower); 293 | if (extToMIMETypeMap.find(ext) == extToMIMETypeMap.end()) { 294 | std::cerr << "Unknown image format " << ext << std::endl; 295 | return false; 296 | } 297 | 298 | mimeType = extToMIMETypeMap[ext]; 299 | 300 | // Load file into memory 301 | TagLib::ByteVector v; 302 | if (loadFileIntoVector(path.toCString(), v) <= 0) { 303 | return false; 304 | } 305 | 306 | TagLib::ID3v2::AttachedPictureFrame *apic = 307 | new TagLib::ID3v2::AttachedPictureFrame(); 308 | apic->setPicture(v); 309 | apic->setMimeType(mimeType); 310 | apic->setType(t); 311 | apic->setDescription(comment); 312 | _i->_file.ID3v2Tag()->addFrame(apic); 313 | _i->_changed = true; 314 | return true; 315 | } 316 | 317 | bool MetaDSF::attachPicture(const TagLib::String &path, 318 | const TagLib::String &ptype) 319 | { 320 | // Determine MIME type 321 | TagLib::String mimeType; 322 | TagLib::String ext = path.substr(path.rfind(".") + 1); 323 | 324 | transform(ext.begin(), ext.end(), ext.begin(), ::tolower); 325 | if (extToMIMETypeMap.find(ext) == extToMIMETypeMap.end()) { 326 | std::cerr << "Unknown image format " << ext << std::endl; 327 | return false; 328 | } 329 | 330 | mimeType = extToMIMETypeMap[ext]; 331 | 332 | // Load file into memory 333 | TagLib::ByteVector v; 334 | if (loadFileIntoVector(path.toCString(), v) <= 0) { 335 | return false; 336 | } 337 | 338 | std::string pt = ptype.toCString(); 339 | TagLib::ID3v2::AttachedPictureFrame *apic = 340 | new TagLib::ID3v2::AttachedPictureFrame(); 341 | TagLib::ID3v2::AttachedPictureFrame::Type t = 342 | static_cast(std::stoi(pt, 0, 16)); 343 | apic->setPicture(v); 344 | apic->setMimeType(mimeType); 345 | apic->setType(t); 346 | _i->_file.ID3v2Tag()->addFrame(apic); 347 | _i->_changed = true; 348 | return true; 349 | } 350 | 351 | int MetaDSF::deletePictures(const TagLib::String &ptype) 352 | { 353 | TagLib::ID3v2::FrameList l = _i->_file.ID3v2Tag()->frameList("APIC"); 354 | TagLib::ID3v2::FrameList dl; // a list of frames to be deleted 355 | TagLib::ID3v2::FrameList::ConstIterator it; 356 | std::string pt = ptype.toCString(); 357 | // retrieve a list of frames that matches the given type 358 | for (it = l.begin(); it != l.end(); it++) { 359 | TagLib::ID3v2::AttachedPictureFrame *f = 360 | static_cast(*it); 361 | TagLib::ID3v2::AttachedPictureFrame::Type t = 362 | static_cast(std::stoi(pt, 363 | 0, 16)); 364 | if (f->type() == t) { 365 | dl.append(f); 366 | } 367 | } 368 | 369 | _i->deleteFrames(dl); 370 | _i->_changed = true; 371 | return dl.size(); 372 | } 373 | 374 | bool MetaDSF::exportPictures(const char *prefix) const 375 | { 376 | std::map counter; 377 | TagLib::ID3v2::FrameList l = _i->_file.ID3v2Tag()->frameList("APIC"); 378 | TagLib::ID3v2::FrameList::ConstIterator it; 379 | for (it = l.begin(); it != l.end(); ++it) { 380 | TagLib::ID3v2::AttachedPictureFrame *f = 381 | static_cast(*it); 382 | std::string fname = prefix; 383 | std::string tname = picTypeDesc[f->type()].toCString(); 384 | std::string ext = MIMETypeToExtMap[f->mimeType()].toCString(); 385 | if (counter.find(tname) == counter.end()) 386 | counter[tname] = 1; 387 | else 388 | counter[tname] += 1; 389 | fname += "_"; 390 | fname += tname; 391 | fname += "_"; 392 | fname += std::to_string(counter[tname]); 393 | fname += "."; 394 | fname += ext; 395 | //std::cout << "fname = " << fname << std::endl; 396 | writeFileFromVector(fname.c_str(), f->picture()); 397 | } 398 | return true; 399 | } 400 | 401 | void MetaDSF::setID3v2Version(int v) 402 | { 403 | if (v < 3 || v > 4) { 404 | _i->_ID3v2_version = 4; 405 | } else { 406 | _i->_ID3v2_version = v; 407 | } 408 | } 409 | 410 | void MetaDSF::setEncoding(const TagLib::String::Type type) 411 | { 412 | _i->_encoding = type; 413 | } 414 | 415 | void MetaDSF::setEncoding(const TagLib::String &name) 416 | { 417 | if (!isValidEncoding(name)) { 418 | _i->_encoding = TagLib::String::UTF8; 419 | } else { 420 | _i->_encoding = encodingType[name]; 421 | } 422 | } 423 | 424 | const TagLib::String::Type MetaDSF::getEncTypeByName(const TagLib::String &name) 425 | { 426 | return encodingType[name]; 427 | } 428 | 429 | const TagLib::String &MetaDSF::getFrameNameByID(const TagLib::String &id) 430 | { 431 | return frameIDToNameMap[id]; 432 | } 433 | 434 | bool MetaDSF::isValidEncoding(const TagLib::String &name) { 435 | if (encodingType.find(name) == encodingType.end()) 436 | return false; 437 | return true; 438 | } 439 | 440 | bool MetaDSF::isValidImage(const TagLib::String &file) { 441 | TagLib::String ext = file.substr(file.rfind(".") + 1); 442 | transform(ext.begin(), ext.end(), ext.begin(), ::tolower); 443 | if (extToMIMETypeMap.find(ext) == extToMIMETypeMap.end()) 444 | return false; 445 | return true; 446 | } 447 | 448 | bool MetaDSF::isValidFrameID(const TagLib::String &id) { 449 | if (frameIDToNameMap.find(id) == frameIDToNameMap.end()) 450 | return false; 451 | return true; 452 | } 453 | 454 | //// Private //// 455 | void MetaDSF::MetaDSFImpl::deleteFrames(const TagLib::ID3v2::FrameList &l) 456 | { 457 | TagLib::ID3v2::FrameList::ConstIterator it; 458 | 459 | for (it = l.begin(); it != l.end(); it++) { 460 | _file.ID3v2Tag()->removeFrame(*it); 461 | } 462 | } 463 | 464 | // Too bad can't use STL copy alogirthm.... 465 | // copy(src.begin(), src.end(), back_inserter(dest)); 466 | void MetaDSF::MetaDSFImpl::dupFrameList(const TagLib::ID3v2::FrameList &src, 467 | TagLib::ID3v2::FrameList &dest) 468 | { 469 | TagLib::ID3v2::FrameList::ConstIterator it; 470 | 471 | for (it = src.begin(); it != src.end(); it++) { 472 | dest.append(*it); 473 | } 474 | } 475 | 476 | int MetaDSF::MetaDSFImpl::deleteTags(const TagLib::String &key) { 477 | TagLib::ID3v2::FrameList l; 478 | if (key == "") { 479 | l = _file.ID3v2Tag()->frameList(); 480 | } else { 481 | l = _file.ID3v2Tag()->frameList(key.toCString()); 482 | } 483 | TagLib::ID3v2::FrameList ll; 484 | 485 | dupFrameList(l, ll); 486 | deleteFrames(ll); 487 | _changed = true; 488 | return ll.size(); 489 | } 490 | 491 | /////////// static members /////////// 492 | StringVector MetaDSF::channelTypeDesc = { 493 | "Dummy", "Mono", "Stereo", "3 Channels", "Quad", "4 Channels", 494 | "5 Channels", "5.1 Channels" }; 495 | 496 | std::vector MetaDSF::picType = { 497 | TagLib::ID3v2::AttachedPictureFrame::Other, 498 | TagLib::ID3v2::AttachedPictureFrame::FileIcon, 499 | TagLib::ID3v2::AttachedPictureFrame::OtherFileIcon, 500 | TagLib::ID3v2::AttachedPictureFrame::FrontCover, 501 | TagLib::ID3v2::AttachedPictureFrame::BackCover, 502 | TagLib::ID3v2::AttachedPictureFrame::LeafletPage, 503 | TagLib::ID3v2::AttachedPictureFrame::Media, 504 | TagLib::ID3v2::AttachedPictureFrame::LeadArtist, 505 | TagLib::ID3v2::AttachedPictureFrame::Artist, 506 | TagLib::ID3v2::AttachedPictureFrame::Conductor, 507 | TagLib::ID3v2::AttachedPictureFrame::Band, 508 | TagLib::ID3v2::AttachedPictureFrame::Composer, 509 | TagLib::ID3v2::AttachedPictureFrame::Lyricist, 510 | TagLib::ID3v2::AttachedPictureFrame::RecordingLocation, 511 | TagLib::ID3v2::AttachedPictureFrame::DuringRecording, 512 | TagLib::ID3v2::AttachedPictureFrame::DuringPerformance, 513 | TagLib::ID3v2::AttachedPictureFrame::MovieScreenCapture, 514 | TagLib::ID3v2::AttachedPictureFrame::ColouredFish, 515 | TagLib::ID3v2::AttachedPictureFrame::Illustration, 516 | TagLib::ID3v2::AttachedPictureFrame::BandLogo, 517 | TagLib::ID3v2::AttachedPictureFrame::PublisherLogo 518 | }; 519 | 520 | StringVector MetaDSF::picTypeDesc = { 521 | "Other", 522 | "FileIcon", 523 | "OtherFileIcon", 524 | "FrontCover", 525 | "BackCover", 526 | "LeafletPage", 527 | "Media", 528 | "LeadArtist", 529 | "Artist", 530 | "Conductor", 531 | "Band", 532 | "Composer", 533 | "Lyricist", 534 | "RecordingLocation", 535 | "DuringRecording", 536 | "DuringPerformance", 537 | "MovieScreenCapture", 538 | "ColouredFish", 539 | "Illustration", 540 | "BandLogo", 541 | "PublisherLogo" 542 | }; 543 | 544 | std::map MetaDSF::encodingType = { 545 | { "UTF8", TagLib::String::UTF8 }, 546 | { "LATIN1", TagLib::String::Latin1 }, 547 | { "UTF16", TagLib::String::UTF16 }, 548 | { "UTF16LE", TagLib::String::UTF16LE }, 549 | { "UTF16BE", TagLib::String::UTF16BE } 550 | }; 551 | 552 | 553 | StringMap MetaDSF::frameIDToNameMap = { 554 | { "TALB","ALBUM" }, 555 | { "TBPM","BPM" }, 556 | { "TCOM","COMPOSER" }, 557 | { "TCON","GENRE" }, 558 | { "TCOP","COPYRIGHT" }, 559 | { "TDEN","ENCODINGTIME" }, 560 | { "TDLY","PLAYLISTDELAY" }, 561 | { "TDOR","ORIGINALDATE" }, 562 | { "TDRC","DATE" }, 563 | { "TDRL","RELEASEDATE" }, 564 | { "TDTG","TAGGINGDATE" }, 565 | { "TENC","ENCODEDBY" }, 566 | { "TEXT","LYRICIST" }, 567 | { "TFLT","FILETYPE" }, 568 | { "TIT1","CONTENTGROUP" }, 569 | { "TIT2","TITLE" }, 570 | { "TIT3","SUBTITLE" }, 571 | { "TKEY","INITIALKEY" }, 572 | { "TLAN","LANGUAGE" }, 573 | { "TLEN","LENGTH" }, 574 | { "TMED","MEDIA" }, 575 | { "TMOO","MOOD" }, 576 | { "TOAL","ORIGINALALBUM" }, 577 | { "TOFN","ORIGINALFILENAME" }, 578 | { "TOLY","ORIGINALLYRICIST" }, 579 | { "TOPE","ORIGINALARTIST" }, 580 | { "TOWN","OWNER" }, 581 | { "TPE1","ARTIST" }, 582 | { "TPE2","ALBUMARTIST" }, 583 | { "TPE2","PERFORMER" }, 584 | { "TPE3","CONDUCTOR" }, 585 | { "TPE4","REMIXER" }, 586 | { "TPOS","DISCNUMBER" }, 587 | { "TPRO","PRODUCEDNOTICE" }, 588 | { "TPUB","LABEL" }, 589 | { "TRCK","TRACKNUMBER" }, 590 | { "TRSN","RADIOSTATION" }, 591 | { "TRSO","RADIOSTATIONOWNER" }, 592 | { "TSOA","ALBUMSORT" }, 593 | { "TSOP","ARTISTSORT" }, 594 | { "TSOT","TITLESORT" }, 595 | { "TSO2","ALBUMARTISTSORT" }, 596 | { "TSRC","ISRC" }, 597 | { "TSSE","ENCODING" }, 598 | { "WCOP","COPYRIGHTURL" }, 599 | { "WOAF","FILEWEBPAGE" }, 600 | { "WOAR","ARTISTWEBPAGE" }, 601 | { "WOAS","AUDIOSOURCEWEBPAGE" }, 602 | { "WORS","RADIOSTATIONWEBPAGE" }, 603 | { "WPAY","PAYMENTWEBPAGE" }, 604 | { "WPUB","PUBLISHERWEBPAGE" }, 605 | { "COMM","COMMENT" }, 606 | { "TRDA","DATE" }, 607 | { "TDAT","DATE" }, 608 | { "TYER","DATE" }, 609 | { "TIME","DATE" }, 610 | { "TCMP","ITUNESCOMPILATIONFLAG" } // not in ID3v2 specs but wildly used 611 | //{ "TMCL","MUSICIANCREDITS" }, 612 | //{ "TIPL","INVOLVEDPEOPLE" }, 613 | //{ "WXXX","URL" } 614 | }; 615 | 616 | StringMap MetaDSF::extToMIMETypeMap = { 617 | { "jpg","image/jpeg" }, 618 | { "jpe","image/jpeg" }, 619 | { "jpeg","image/jpeg" }, 620 | { "gif","image/gif" }, 621 | { "tif","image/tiff" }, 622 | { "tiff","image/tiff" } 623 | }; 624 | 625 | StringMap MetaDSF::MIMETypeToExtMap = { 626 | { "image/jpeg", "jpg" }, 627 | { "image/gif", "gif" }, 628 | { "image/tiff", "tiff" } 629 | }; 630 | -------------------------------------------------------------------------------- /src/metadsf.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | copyright : (C) 2014 by Peking Duck Labs 3 | email : pekingducklabs@gmail.com 4 | ***************************************************************************/ 5 | 6 | /*************************************************************************** 7 | * This library is free software; you can redistribute it and/or modify * 8 | * it under the terms of the GNU Lesser General Public License version * 9 | * 2.1 as published by the Free Software Foundation. * 10 | * * 11 | * This library is distributed in the hope that it will be useful, but * 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of * 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 14 | * Lesser General Public License for more details. * 15 | * * 16 | * You should have received a copy of the GNU Lesser General Public * 17 | * License along with this library; if not, write to the Free Software * 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 19 | * 02110-1301 USA * 20 | ***************************************************************************/ 21 | 22 | #ifndef _METADSF_H_ 23 | #define _METADSF_H_ 24 | 25 | #include "typedefs.h" 26 | 27 | #include 28 | 29 | 30 | class MetaDSF { 31 | public: 32 | // initializes the above static members 33 | 34 | MetaDSF(const char *); 35 | ~MetaDSF(); 36 | 37 | // Check if object initializes OK 38 | bool isOK() const; 39 | 40 | // Save changes to disk 41 | bool save(); 42 | 43 | // Delete a picture. Return the number of pictures deleted 44 | int deletePictures(const TagLib::String &ptype); 45 | 46 | // Attach a picture of type ptype (default is "03" which is front cover) 47 | bool attachPicture(const TagLib::String &file, 48 | const TagLib::String &ptype = "03"); 49 | 50 | bool attachPicture(const TagLib::String &file, 51 | const TagLib::ID3v2::AttachedPictureFrame::Type, 52 | const TagLib::String &comment = ""); 53 | 54 | bool exportPictures(const char *prefix) const; 55 | 56 | // Set simple textual data 57 | int setTag(const TagLib::String &key, 58 | const TagLib::String &val, bool replace = false); 59 | 60 | // Same as above, but takes value as a String list 61 | int setTag(const TagLib::String &key, 62 | const TagLib::StringList &vals, bool replace = false); 63 | 64 | // TXXX - user-defined text 65 | int setTagTXXX(const TagLib::String &desc, 66 | const TagLib::String &vals, bool replace = false); 67 | 68 | // WXXX - user-defined URL 69 | int setTagWXXX(const TagLib::String &url, 70 | const TagLib::String &urlDesc, bool replace = false); 71 | 72 | // TIPL - people involved. 73 | int setTagTIPL(const TagLib::PropertyMap &, bool replace = false); 74 | 75 | // TMCL - music credit list. 76 | int setTagTMCL(const TagLib::PropertyMap &, bool replace = false); 77 | 78 | // Handy functions 79 | // (All delete existing data first) 80 | /* void setArtist(const TagLib::String &); */ 81 | /* void setGenre(const TagLib::String &); */ 82 | /* void setTitle(const TagLib::String &); */ 83 | /* void setAlbum(const TagLib::String &); */ 84 | /* void setYear(unsigned int); */ 85 | /* void setTrack(unsigned int); */ 86 | 87 | 88 | // Delete tags by key. Return the number of tags deleted (same key can 89 | // appear more than once) 90 | int deleteTags(const TagLib::String &key); 91 | 92 | // Delete all tags (frames). Return the number of frames deleted 93 | int deleteAllTags(); 94 | 95 | // Dump file info to cout 96 | void printInfo(const char *prefix = "") const; 97 | 98 | // Dump tags to cout 99 | void printTags(const char *prefix = "") const; 100 | 101 | // Set ID3v2 version. Can be either 3 or 4. 102 | void setID3v2Version(int); 103 | 104 | // Set encoding 105 | void setEncoding(const TagLib::String &name); 106 | void setEncoding(const TagLib::String::Type type); 107 | 108 | static const TagLib::String &getChannelTypeDesc(unsigned int pos); 109 | static const TagLib::String &getPicTypeDesc(unsigned int pos); 110 | static const TagLib::String &getFrameNameByID(const TagLib::String &id); 111 | static const TagLib::String::Type getEncTypeByName(const TagLib::String &name); 112 | static bool isValidEncoding(const TagLib::String &name); 113 | static bool isValidImage(const TagLib::String &file); 114 | static bool isValidFrameID(const TagLib::String &id); 115 | static bool isValidPicType(uint i) { 116 | return (i < picType.size()); 117 | } 118 | private: 119 | MetaDSF(const MetaDSF &); 120 | MetaDSF &operator=(const MetaDSF &); 121 | 122 | static StringVector channelTypeDesc; 123 | static StringVector picTypeDesc; 124 | static std::vector picType; 125 | static std::map encodingType; 126 | static StringMap frameIDToNameMap; 127 | static StringMap extToMIMETypeMap; 128 | static StringMap MIMETypeToExtMap; 129 | 130 | class MetaDSFImpl; 131 | MetaDSFImpl *_i; 132 | }; 133 | 134 | #endif 135 | -------------------------------------------------------------------------------- /src/mkdsf.cpp: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | copyright : (C) 2014 by Peking Duck Labs 3 | email : pekingducklabs@gmail.com 4 | ***************************************************************************/ 5 | 6 | /*************************************************************************** 7 | * This library is free software; you can redistribute it and/or modify * 8 | * it under the terms of the GNU Lesser General Public License version * 9 | * 2.1 as published by the Free Software Foundation. * 10 | * * 11 | * This library is distributed in the hope that it will be useful, but * 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of * 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 14 | * Lesser General Public License for more details. * 15 | * * 16 | * You should have received a copy of the GNU Lesser General Public * 17 | * License along with this library; if not, write to the Free Software * 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 19 | * 02110-1301 USA * 20 | ***************************************************************************/ 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | class fwriter { 27 | public: 28 | fwriter(FILE *f) : _f(f), _total(0) {} 29 | ~fwriter() {} 30 | void write(const void *ptr, size_t n) { 31 | _total += fwrite(ptr, 1, n, _f); 32 | } 33 | void print() { 34 | std::cout << _total << " bytes written" << std::endl; 35 | } 36 | private: 37 | FILE *_f; 38 | size_t _total; 39 | }; 40 | 41 | // turn 64-bit integer to raw 42 | inline char *u64raw(uint64_t n, char *buf) { 43 | for (int i = 0; i < 8; i++) { 44 | buf[i] = ((0xff << (i * 8)) & n) >> (i * 8); 45 | } 46 | return buf; 47 | } 48 | 49 | // turn 32-bit integer to raw 50 | inline char *u32raw(uint32_t n, char *buf) { 51 | for (int i = 0; i < 4; i++) { 52 | buf[i] = ((0xff << (i * 8)) & n) >> (i * 8); 53 | } 54 | return buf; 55 | } 56 | 57 | int main(int argc, char *argv[]) { 58 | // Create a minimal DSF file for testing 59 | 60 | if (argc != 2) { 61 | std::cerr << "file name not specified" << std::endl; 62 | exit(2); 63 | } 64 | 65 | FILE *f = fopen(argv[1], "w"); 66 | if (!f) { 67 | std::cerr << "file name not specified" << std::endl; 68 | exit(2); 69 | } 70 | 71 | fwriter w(f); 72 | 73 | std::string s = "DSD "; 74 | w.write(s.c_str(), 4); // dsd chunk header 75 | 76 | char buf[8192]; 77 | 78 | w.write(u64raw(28, buf), 8); // dsd header size 79 | w.write(u64raw(8284, buf), 8); // file size 80 | w.write(u64raw(0, buf), 8); // pointer to id3v2 metadata 81 | 82 | s = "fmt "; 83 | w.write(s.c_str(), 4); // FMT chunk header 84 | w.write(u64raw(52, buf), 8); // FMT chunk size 85 | w.write(u32raw(1, buf), 4); // format version 86 | w.write(u32raw(0, buf), 4); // format id 87 | w.write(u32raw(2, buf), 4); // channel type 88 | w.write(u32raw(2, buf), 4); // channel number 89 | w.write(u32raw(2822400, buf), 4); // sampling freq. 90 | w.write(u32raw(1, buf), 4); // bits per sample 91 | w.write(u64raw(8192, buf), 8); // sampling count 92 | w.write(u32raw(4096, buf), 4); // block size per channel 93 | w.write(u32raw(0, buf), 4); // reserved 94 | 95 | s = "data"; // data chunk 96 | w.write(s.c_str(), 4); 97 | w.write(u64raw(8204, buf), 4); // data chunk size 98 | 99 | memset(&buf[0], 0, 8192); 100 | w.write(&buf[0], 8192); //sample data: 8192 samples = 2 x 4096 which 101 | //is the block size per channel 102 | 103 | w.print(); 104 | 105 | fclose(f); 106 | } 107 | -------------------------------------------------------------------------------- /src/options.cpp: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | copyright : (C) 2014 by Peking Duck Labs 3 | email : pekingducklabs@gmail.com 4 | ***************************************************************************/ 5 | 6 | /*************************************************************************** 7 | * This library is free software; you can redistribute it and/or modify * 8 | * it under the terms of the GNU Lesser General Public License version * 9 | * 2.1 as published by the Free Software Foundation. * 10 | * * 11 | * This library is distributed in the hope that it will be useful, but * 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of * 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 14 | * Lesser General Public License for more details. * 15 | * * 16 | * You should have received a copy of the GNU Lesser General Public * 17 | * License along with this library; if not, write to the Free Software * 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 19 | * 02110-1301 USA * 20 | ***************************************************************************/ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include "optionparser.h" 27 | #include "options.h" 28 | #include "utils.h" 29 | 30 | //namespace myopt { 31 | 32 | enum OptionIndex { 33 | UNKNOWN, 34 | HELP, 35 | SHOW_INFO, 36 | SHOW_TAGS, 37 | ENCODING, 38 | VER, 39 | ID3V2_VERSION, 40 | ADD_TAG, 41 | ADD_TAGS_FROM_FILE, 42 | SET_TAG, 43 | SET_TAGS_FROM_FILE, 44 | REMOVE_TAGS, 45 | REMOVE_EVERYTHING, 46 | REMOVE_ALL_PICTURES, 47 | IMPORT_PICTURE, 48 | REMOVE_PICTURES, 49 | EXPORT_PICTURES, 50 | //DRY_RUN 51 | }; 52 | 53 | const option::Descriptor usage[] = { 54 | { UNKNOWN, 0, "", "", option::Arg::None, "Usage: metadsf [options] files..." }, 55 | { HELP, 0, "h", "help", option::Arg::None, "--help, -h\n Print usage and exit" }, 56 | { VER, 0, "v", "version", option::Arg::None, "--version, -v\n Display version info and exit" }, 57 | { SHOW_INFO, 0, "i", "show-info", option::Arg::None, "--show-info, -i\n Print file info" }, 58 | { SHOW_TAGS, 0, "t", "show-tags", option::Arg::None, "--show-tags, -t\n Print tags" }, 59 | { ENCODING, 0, "e", "encoding", option::Arg::Optional, "--encoding, -e=...\n Set encoding. Valid encodings are: UTF8(default), LATIN1, UTF16, UTF16LE, UTF16BE" }, 60 | { ID3V2_VERSION, 0, "", "id3v2-version", option::Arg::Optional, "--id3v2-version\n Which ID3V2 version to save. Can be either 3 or 4" }, 61 | 62 | { ADD_TAG, 0, "a", "add-tag", option::Arg::Optional, "--add-tag, -a==\n Add tag" }, 63 | { ADD_TAGS_FROM_FILE, 0, "", "add-tags-from-file", option::Arg::Optional, "--add-tags-from-file=\n Add tags from a file, one per line (TAG=VALUE)" }, 64 | { SET_TAG, 0, "s", "set-tag", option::Arg::Optional, "--set-tag, -s=NAME=...\n Set tag. Old value will be overwritten" }, 65 | { SET_TAGS_FROM_FILE, 0, "", "set-tags-from-file", option::Arg::Optional, "--set-tags-from-file=\n Set tags from a file, one per line (TAG=VALUE)" }, 66 | { REMOVE_TAGS, 0, "r", "remove-tags", option::Arg::Optional, "--remove-tags, -r=a,b,c\n Remove ALL occurences of the specified tags" }, 67 | { REMOVE_PICTURES, 0, "", "remove-pictures", option::Arg::Optional, "--remove-pictures=t1,t2,t3\n Remove pictures of the specified types" }, 68 | { REMOVE_EVERYTHING, 0, "", "remove-everything", option::Arg::Optional, "--remove-everything\n Remove *ALL* ID3v2 tags including pictures" }, 69 | { REMOVE_ALL_PICTURES, 0, "", "remove-all-pictures", option::Arg::Optional, "--remove-all-pictures\n Remove ALL pictures" }, 70 | { IMPORT_PICTURE, 0, "p", "import-picture", option::Arg::Optional, "--import-picture, -p=file[|type|comment]\n Import picture into file."}, 71 | { EXPORT_PICTURES, 0, "", "export-all-pictures", option::Arg::Optional, "--export-all-pictures\n Export pictures" }, 72 | //{ DRY_RUN, 0, "d", "dry-run", option::Arg::None, "--dry-run\n Run without saving" }, 73 | { 0, 0, 0, 0, 0, 0 } 74 | }; 75 | 76 | 77 | // These handy functions are defined at the end 78 | 79 | void getOptionPairsToMap(option::Option *o, OptionIndex index, StringMap &m); 80 | int getUniqueReqdArg(option::Option *op, OptionIndex index, TagLib::String &val); 81 | void getOptionsToVector(option::Option *o, OptionIndex index, StringVector &v, 82 | const char *sep = nullptr); 83 | 84 | inline void printOptMultiError(const char *tag) 85 | { 86 | std::cerr << "Multiple --" << tag << " supplied" << std::endl; 87 | } 88 | 89 | inline void printOptArgMissingError(const char *txt) 90 | { 91 | std::cerr << "No " << txt << " specified" << std::endl; 92 | } 93 | 94 | inline void printOptInvalidArgError(const char *txt) { 95 | std::cerr << "Invalid " << txt << std::endl; 96 | } 97 | 98 | void printMap(StringMap &m) { 99 | for (auto &i : m) 100 | std::cout << " [" << i.first << "] [" << i.second << "]" << std::endl; 101 | } 102 | 103 | void printVector(StringVector &v) 104 | { 105 | for (auto &i : v) 106 | std::cout << " " << i << std::endl; 107 | } 108 | 109 | #ifdef XXXX 110 | int main(int argc, char *argv[]) { 111 | StringMap m; 112 | readTagsFromFile("test.csv", m); 113 | for (auto i = begin(m); i != end(m); ++i) { 114 | std::cout << "[" << i->first << "] [" << i->second << "]" << std::endl; 115 | } 116 | } 117 | #endif 118 | 119 | void OptionObj::print() 120 | { 121 | std::cout << "Encoding: " << encoding << std::endl; 122 | std::cout << "Version: " << version << std::endl; 123 | std::cout << "Set Tags File: " << setTagsFile << std::endl; 124 | std::cout << "Add Tags File: " << addTagsFile << std::endl; 125 | std::cout << "Separator: " << separator << std::endl; 126 | std::cout << "Remove everything? " << removeEverything << std::endl; 127 | std::cout << "Remove all pictures? " << removeAllPics << std::endl; 128 | std::cout << "Show tags? " << showTags << std::endl; 129 | std::cout << "Show info? " << showInfo << std::endl; 130 | std::cout << "Export pics? " << exportPics << std::endl; 131 | std::cout << "Dry run? " << dryRun << std::endl; 132 | 133 | std::cout << "File List: " << std::endl; 134 | printVector(fileList); 135 | std::cout << "Remove Tag List: " << std::endl; 136 | printVector(removeTagList); 137 | std::cout << "Add Pic List: " << std::endl; 138 | printVector(addPicList); 139 | std::cout << "Delete Pic List: " << std::endl; 140 | printVector(removePicList); 141 | std::cout << "addTagMap: " << std::endl; 142 | printMap(addTagMap); 143 | //std::cout << "handyMap: " << std::endl; 144 | //printMap(handyMap); 145 | } 146 | 147 | 148 | bool OptionObj::parse(int argc, char *argv[]) 149 | { 150 | option::Stats stats(usage, argc, argv); 151 | option::Option *options = new option::Option[stats.options_max]; 152 | option::Option *buffer = new option::Option[stats.buffer_max]; 153 | 154 | std::unique_ptr pOptions(options); 155 | std::unique_ptr pBuffer(buffer); 156 | 157 | option::Parser op(usage, argc, argv, options, buffer); 158 | 159 | if (op.error()) { 160 | return false; 161 | } 162 | 163 | if (options[HELP].count() >= 1 || options[UNKNOWN]) { 164 | showHelp = true; 165 | return true; 166 | } 167 | 168 | if (options[VER].count() >= 1) { 169 | showVersion = true; 170 | return true; 171 | } 172 | 173 | for (int i = 0; i < op.nonOptionsCount(); ++i) { 174 | fileList.push_back(op.nonOption(i)); 175 | } 176 | 177 | if (fileList.size() == 0) { 178 | std::cerr << "No files specified" << std::endl; 179 | return false; 180 | } 181 | 182 | if (options[SHOW_INFO].count() >= 1) { 183 | showInfo = true; 184 | } 185 | if (options[SHOW_TAGS].count() >= 1) { 186 | showTags = true; 187 | } 188 | if (options[EXPORT_PICTURES].count() >= 1) { 189 | exportPics = true; 190 | } 191 | 192 | // Encoding 193 | int c = getUniqueReqdArg(options, ENCODING, encoding); 194 | if (c > 1) { 195 | printOptMultiError("encoding"); 196 | return false; 197 | } else if (c == -1) { 198 | printOptArgMissingError("encoding"); 199 | return false; 200 | } 201 | 202 | // Separator 203 | // c = getUniqueReqdArg(options, SEPARATOR, separator); 204 | // if (c > 1) { 205 | // std::cerr << "Multiple --separator supplied" << std::endl; 206 | // return false; 207 | // } else if (c == -1) { 208 | // std::cerr << "No separator specified" << std::endl; 209 | // return false; 210 | // } 211 | 212 | // ID3v2 Version 213 | c = getUniqueReqdArg(options, ID3V2_VERSION, version); 214 | if (c > 1) { 215 | std::cerr << "Multiple --id3v2-version supplied" << std::endl; 216 | return false; 217 | } else if (c == -1) { 218 | std::cerr << "No ID3v2 version specified" << std::endl; 219 | return false; 220 | } 221 | 222 | // --remove-tag and 223 | // --remove-everything 224 | //StringMap removeMap; 225 | if (options[REMOVE_EVERYTHING].count() >= 1) { 226 | removeEverything = true; 227 | } else { 228 | getOptionsToVector(options, REMOVE_TAGS, removeTagList, ","); 229 | getOptionsToVector(options, REMOVE_PICTURES, removePicList, ","); 230 | if (options[REMOVE_ALL_PICTURES].count() >= 1) { 231 | removeAllPics = true; 232 | removeTagList.push_back("APIC"); 233 | } 234 | } 235 | 236 | // --set-tags-from-file 237 | //StringMap tmp; 238 | c = getUniqueReqdArg(options, SET_TAGS_FROM_FILE, setTagsFile); 239 | if (c > 1) { 240 | std::cerr << "Multiple --set-tags-from-file supplied" << std::endl; 241 | return false; 242 | } else if (c == -1) { 243 | std::cerr << "--set-tags-from-file: no file specified" << std::endl; 244 | return false; 245 | } 246 | 247 | // --set-tag 248 | //StringMap addMap; 249 | getOptionPairsToMap(options, SET_TAG, addTagMap); 250 | //addMap.insert(tmp.begin(), tmp.end()); 251 | 252 | // --add-tags-from-file 253 | c = getUniqueReqdArg(options, ADD_TAGS_FROM_FILE, addTagsFile); 254 | if (c > 1) { 255 | std::cerr << "Multiple --add-tags-from-file supplied" << std::endl; 256 | return false; 257 | } else if (c == -1) { 258 | std::cerr << "--add-tags-from-file: no file specified" << std::endl; 259 | return false; 260 | } 261 | 262 | // --add-tag 263 | getOptionPairsToMap(options, ADD_TAG, addTagMap); 264 | 265 | // Processing handy commands such as --set-artist/title/.... etc 266 | // std::vector > handyCmds = { 267 | // { "artist", SET_ARTIST }, 268 | // { "title", SET_TITLE }, 269 | // { "genre", SET_GENRE }, 270 | // { "track", SET_TRACK }, 271 | // { "album", SET_ALBUM }, 272 | // { "year", SET_YEAR } 273 | // }; 274 | // for (auto &cmd : handyCmds) { 275 | // TagLib::String val; 276 | // c = getUniqueReqdArg(options, cmd.second, val); 277 | // if (val.size() > 0) { 278 | // handyMap[cmd.first] = val; 279 | // } 280 | // } 281 | 282 | // --import-picture 283 | getOptionsToVector(options, IMPORT_PICTURE, addPicList); 284 | 285 | return true; 286 | } // parse() 287 | 288 | 289 | void getOptionsToVector(option::Option *o, OptionIndex index, StringVector &v, 290 | const char *sep) 291 | { 292 | for (option::Option* opt = o[index]; opt; opt = opt->next()) 293 | if (opt->arg != nullptr) { 294 | if (sep == 0) { 295 | v.push_back(opt->arg); 296 | } else { 297 | StringVector tmp; 298 | split(opt->arg, sep, tmp, false); 299 | for (auto &i : tmp) 300 | v.push_back(i); 301 | } 302 | } 303 | } 304 | 305 | void getOptionPairsToMap(option::Option *o, OptionIndex index, StringMap &m) 306 | { 307 | for (option::Option* opt = o[index]; opt; opt = opt->next()) { 308 | if (opt->arg != nullptr) { 309 | std::string arg = opt->arg; 310 | StringVector v; 311 | split(arg, "=", v, true, 2); 312 | if (v.size() == 1) 313 | m[v[0]] = ""; 314 | else if (v.size() == 2) 315 | m[v[0]] = v[1]; 316 | } 317 | } 318 | } 319 | 320 | // check, if the option is supplied, that it appears only once and comes with 321 | // an argument 322 | int getUniqueReqdArg(option::Option *op, OptionIndex index, TagLib::String &val) 323 | { 324 | if (op[index].count() > 1) { 325 | // multiple occurences 326 | return op[index].count(); 327 | } else if (op[index].count() == 1){ 328 | if (op[index].arg != nullptr && strlen(op[index].arg) > 0) { 329 | // OK 330 | val = op[index].arg; 331 | return 1; 332 | } 333 | // option specific 334 | return -1; 335 | } 336 | return 0; 337 | } 338 | 339 | void OptionObj::printUsage() 340 | { 341 | option::printUsage(std::cout, usage); 342 | } 343 | //} // namespace 344 | -------------------------------------------------------------------------------- /src/options.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | copyright : (C) 2014 by Peking Duck Labs 3 | email : pekingducklabs@gmail.com 4 | ***************************************************************************/ 5 | 6 | /*************************************************************************** 7 | * This library is free software; you can redistribute it and/or modify * 8 | * it under the terms of the GNU Lesser General Public License version * 9 | * 2.1 as published by the Free Software Foundation. * 10 | * * 11 | * This library is distributed in the hope that it will be useful, but * 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of * 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 14 | * Lesser General Public License for more details. * 15 | * * 16 | * You should have received a copy of the GNU Lesser General Public * 17 | * License along with this library; if not, write to the Free Software * 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 19 | * 02110-1301 USA * 20 | ***************************************************************************/ 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | #include "typedefs.h" 27 | 28 | #ifndef _OPTIONS_H_ 29 | #define _OPTIONS_H_ 30 | 31 | //namespace myopt { 32 | 33 | class OptionObj { 34 | public: 35 | TagLib::String encoding; 36 | TagLib::String version; 37 | TagLib::String setTagsFile; 38 | TagLib::String addTagsFile; 39 | TagLib::String separator; 40 | StringMap addTagMap; 41 | //StringMap handyMap; 42 | StringVector fileList; 43 | StringVector addPicList; 44 | StringVector removeTagList; 45 | StringVector removePicList; 46 | StringVector exportPicList; 47 | bool showTags; 48 | bool showInfo; 49 | bool removeEverything; 50 | bool dryRun; 51 | bool removeAllPics; 52 | bool exportPics; 53 | bool showVersion; 54 | bool showHelp; 55 | 56 | OptionObj() : 57 | showTags(false), 58 | showInfo(false), 59 | removeEverything(false), 60 | dryRun(false), 61 | removeAllPics(false), 62 | exportPics(false), 63 | showVersion(false), 64 | showHelp(false) {} 65 | 66 | void printUsage(); 67 | void print(); 68 | bool parse(int argc, char *argv[]); 69 | }; 70 | 71 | //} // namespace 72 | 73 | #endif 74 | -------------------------------------------------------------------------------- /src/typedefs.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | copyright : (C) 2014 by Peking Duck Labs 3 | email : pekingducklabs@gmail.com 4 | ***************************************************************************/ 5 | 6 | /*************************************************************************** 7 | * This library is free software; you can redistribute it and/or modify * 8 | * it under the terms of the GNU Lesser General Public License version * 9 | * 2.1 as published by the Free Software Foundation. * 10 | * * 11 | * This library is distributed in the hope that it will be useful, but * 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of * 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 14 | * Lesser General Public License for more details. * 15 | * * 16 | * You should have received a copy of the GNU Lesser General Public * 17 | * License along with this library; if not, write to the Free Software * 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 19 | * 02110-1301 USA * 20 | ***************************************************************************/ 21 | 22 | #ifndef _TYPEDEFS_H_ 23 | #define _TYPEDEFS_H_ 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | typedef std::map StringMap; 31 | typedef std::pair StringPair; 32 | typedef std::vector StringVector; 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /src/utils.cpp: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | copyright : (C) 2014 by Peking Duck Labs 3 | email : pekingducklabs@gmail.com 4 | ***************************************************************************/ 5 | 6 | /*************************************************************************** 7 | * This library is free software; you can redistribute it and/or modify * 8 | * it under the terms of the GNU Lesser General Public License version * 9 | * 2.1 as published by the Free Software Foundation. * 10 | * * 11 | * This library is distributed in the hope that it will be useful, but * 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of * 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 14 | * Lesser General Public License for more details. * 15 | * * 16 | * You should have received a copy of the GNU Lesser General Public * 17 | * License along with this library; if not, write to the Free Software * 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 19 | * 02110-1301 USA * 20 | ***************************************************************************/ 21 | 22 | #include 23 | #include 24 | #include "utils.h" 25 | 26 | //namespace utils { 27 | 28 | void split(const std::string &s, 29 | const std::string &delim, 30 | StringVector &result, 31 | const bool keep_empty, 32 | unsigned int upTo) 33 | { 34 | if (delim.empty()) { 35 | result.push_back(s); 36 | return; 37 | } 38 | std::string::const_iterator substart = s.begin(), subend; 39 | while (true) { 40 | subend = std::search(substart, s.end(), delim.begin(), delim.end()); 41 | std::string temp(substart, subend); 42 | if (keep_empty || !temp.empty()) { 43 | result.push_back(temp); 44 | --upTo; 45 | } 46 | if (subend == s.end()) { 47 | break; 48 | } 49 | substart = subend + delim.size(); 50 | if (upTo == 1) { 51 | std::string rest(substart, s.end()); 52 | result.push_back(rest); 53 | break; 54 | } 55 | } 56 | } 57 | 58 | bool readPairsFromFile(const char *path, StringMap &m) 59 | { 60 | std::ifstream infile(path); 61 | // check if open was successful 62 | 63 | if (!infile.good()) { 64 | std::cerr << "Failed to open " << path << std::endl; 65 | return false; 66 | } 67 | 68 | std::string line; 69 | int i = 0; 70 | while (std::getline(infile, line)) { 71 | ++i; 72 | StringVector v; 73 | split(line, "=", v, false, 2); 74 | if (v.size() != 2) { 75 | std::cerr << path << ": line " << i << " is malformed" << std::endl; 76 | return false; 77 | } 78 | if (v[0].size() == 0) { 79 | std::cerr << path << ": line " << i << " tag name missing"; 80 | return false; 81 | } 82 | if (v[1].size() == 0) { 83 | std::cerr << path << ": line " << i << " tag value missing" << std::endl; 84 | return false; 85 | } 86 | //std::cout << i << ": key=[" << key << "], val=[" << val << "]" << std::endl; 87 | m[v[0]] = v[1]; 88 | } 89 | return true; 90 | } 91 | 92 | size_t loadFileIntoVector(const char *path, TagLib::ByteVector &v) 93 | { 94 | std::ifstream is(path, std::ifstream::binary); 95 | 96 | if (!is.good()) { 97 | return 0; 98 | } 99 | 100 | // get the file size and create an appropriate buffer 101 | is.seekg(0, is.end); 102 | size_t len = is.tellg(); 103 | is.seekg(0, is.beg); 104 | 105 | char *buf = new char[len]; 106 | 107 | // read into buffer 108 | is.read(buf, len); 109 | v.setData(buf, len); 110 | 111 | is.close(); 112 | delete[] buf; 113 | 114 | return len; 115 | } 116 | 117 | bool isReadableFile(const char *path) 118 | { 119 | std::ifstream is(path, std::ifstream::binary); 120 | 121 | if (!is.good()) 122 | return false; 123 | return true; 124 | } 125 | 126 | bool stringToLong(const std::string &s, long &l) 127 | { 128 | try { 129 | l = std::stol(s); 130 | return true; 131 | } catch (std::invalid_argument&) { 132 | return false; 133 | } 134 | } 135 | 136 | bool writeFileFromVector(const char *path, const TagLib::ByteVector &v) { 137 | std::ofstream o(path, std::ofstream::binary); 138 | if (!o) { 139 | return false; 140 | } 141 | o.write(v.data(), v.size()); 142 | return true; 143 | } 144 | 145 | //} // namespace 146 | -------------------------------------------------------------------------------- /src/utils.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | copyright : (C) 2014 by Peking Duck Labs 3 | email : pekingducklabs@gmail.com 4 | ***************************************************************************/ 5 | 6 | /*************************************************************************** 7 | * This library is free software; you can redistribute it and/or modify * 8 | * it under the terms of the GNU Lesser General Public License version * 9 | * 2.1 as published by the Free Software Foundation. * 10 | * * 11 | * This library is distributed in the hope that it will be useful, but * 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of * 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 14 | * Lesser General Public License for more details. * 15 | * * 16 | * You should have received a copy of the GNU Lesser General Public * 17 | * License along with this library; if not, write to the Free Software * 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 19 | * 02110-1301 USA * 20 | ***************************************************************************/ 21 | 22 | #ifndef _UTILS_H_ 23 | #define _UTILS_H_ 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include "typedefs.h" 30 | 31 | bool readPairsFromFile(const char *, StringMap &); 32 | 33 | void split(const std::string &s, 34 | const std::string &delim, 35 | StringVector &v, 36 | const bool keep_empty, 37 | unsigned int upTo = 0); 38 | 39 | size_t loadFileIntoVector(const char *path, TagLib::ByteVector &v); 40 | 41 | bool isReadableFile(const char *path); 42 | 43 | bool stringToLong(const std::string &, long &l); 44 | 45 | bool writeFileFromVector(const char *path, const TagLib::ByteVector &v); 46 | 47 | #endif 48 | --------------------------------------------------------------------------------